deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
template_constraints.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2003 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_template_constraints_h
14#define dealii_template_constraints_h
15
16
17#include <deal.II/base/config.h>
18
22
24
25#include <complex>
26#include <type_traits>
27#include <utility>
28
29
31
32// Detection idiom adapted from Version 2 of the C++ Extensions for Library
33// Fundamentals, ISO/IEC TS 19568:2017
34namespace internal
35{
41 namespace SupportsOperation
42 {
43 template <class...>
44 using void_t = void;
45
52 template <class Default,
53 class AlwaysVoid,
54 template <class...>
55 class Op,
56 class... Args>
57 struct detector
58 {
59 using value_t = std::false_type;
60 using type = Default;
61 };
62
75 template <class Default, template <class...> class Op, class... Args>
76 struct detector<Default, void_t<Op<Args...>>, Op, Args...>
77 {
78 using value_t = std::true_type;
79 using type = Op<Args...>;
80 };
81
82
88 {};
89
94 struct nonesuch : private nonesuch_base
95 {
96 ~nonesuch() = delete;
97 nonesuch(const nonesuch &) = delete;
98 void
99 operator=(const nonesuch &) = delete;
100 };
101
102 template <class Default, template <class...> class Op, class... Args>
103 using detected_or = detector<Default, void, Op, Args...>;
104
105 template <template <class...> class Op, class... Args>
106 using is_detected = typename detected_or<nonesuch, Op, Args...>::value_t;
107
108 template <template <class...> class Op, class... Args>
109 using detected_t = typename detected_or<nonesuch, Op, Args...>::type;
110
111 template <class Default, template <class...> class Op, class... Args>
112 using detected_or_t = typename detected_or<Default, Op, Args...>::type;
113
114 template <class Expected, template <class...> class Op, class... Args>
115 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
116
117 template <class To, template <class...> class Op, class... Args>
119 std::is_convertible<detected_t<Op, Args...>, To>;
120 } // namespace SupportsOperation
121
122
157 template <template <class...> class Op, class... Args>
158 constexpr bool is_supported_operation =
160} // namespace internal
161
162
163
164namespace internal
165{
166 namespace TemplateConstraints
167 {
176 template <bool... Values>
177 struct all_true
178 {
179 static constexpr bool value = (Values && ...);
180 };
181
182
187 template <bool... Values>
188 struct any_true
189 {
190 static constexpr bool value = (Values || ...);
191 };
192 } // namespace TemplateConstraints
193} // namespace internal
194
201template <class Base, class... Derived>
203{
205 std::is_base_of_v<Base, Derived>...>::value;
206};
207
208
209
216template <typename Type, class... Types>
218{
220 std::is_same_v<Type, Types>...>::value;
221};
222
223
224
231template <typename Type, class... Types>
233{
235 std::is_same_v<Type, Types>...>::value;
236};
237
238
239
240/*
241 * A generalization of `std::enable_if` that only works if
242 * <i>all</i> of the given boolean template parameters are
243 * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
244 * for what `std::enable_if` does.
245 *
246 * @note
247 * In contrast to `std::enable_if`, this template has no additional
248 * template type (which for `std::enable_if` is defaulted to `void`).
249 * As a consequence, this structure cannot be used for anything other
250 * than enabling or disabling a template declaration; in particular
251 * it cannot be used to set the return type of a function as one might
252 * do with something like
253 * @code
254 * template <typename T>
255 * typename std::enable_if<std::is_floating_point_v<T>, T>::type
256 * abs (const T t);
257 * @endcode
258 * which declares a function template `abs()` that can only be
259 * instantiated if `T` is a floating point type; this function then
260 * returns an object of type `T` as indicated by the last argument to
261 * `std::enable_if`. The reason `enable_if_all` does not allow providing
262 * this additional type is that variadic templates (here, the list of
263 * `bool` arguments) must be the last template argument.
264 */
265template <bool... Values>
267 : std::enable_if<internal::TemplateConstraints::all_true<Values...>::value>
268{};
269
270
271
272/*
273 * A generalization of `std::enable_if_t` that only works if
274 * <i>all</i> of the given boolean template parameters are
275 * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
276 * for what `std::enable_if_t` does.
277 *
278 * @note
279 * In contrast to `std::enable_if_t`, this template has no additional
280 * template type (which for `std::enable_if` is defaulted to `void`).
281 * As a consequence, this structure cannot be used for anything other
282 * than enabling or disabling a template declaration; in particular
283 * it cannot be used to set the return type of a function as one might
284 * do with something like
285 * @code
286 * template <typename T>
287 * std::enable_if_t<std::is_floating_point_v<T>, T>
288 * abs (const T t);
289 * @endcode
290 * which declares a function template `abs()` that can only be
291 * instantiated if `T` is a floating point type; this function then
292 * returns an object of type `T` as indicated by the last argument to
293 * `std::enable_if`. The reason `enable_if_all` does not allow providing
294 * this additional type is that variadic templates (here, the list of
295 * `bool` arguments) must be the last template argument.
296 */
297template <bool... Values>
298using enable_if_all_t = typename enable_if_all<Values...>::type;
299
300
306template <typename T>
308 decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()));
309
310template <typename T>
311constexpr bool has_begin_and_end =
312 internal::is_supported_operation<begin_and_end_t, T>;
313
314
320template <typename ArgType, typename ValueType>
322{
323 ValueType value;
324 ValueType
325 operator()(const ArgType &)
326 {
327 return value;
328 }
329};
330
331
332
350{
355 template <typename T>
356 static bool
357 equal(const T *p1, const T *p2)
358 {
359 return (p1 == p2);
360 }
361
362
369 template <typename T, typename U>
370 static bool
371 equal(const T *, const U *)
372 {
373 return false;
374 }
375};
376
377
378
379namespace internal
380{
391 template <typename T, typename U>
393 {
394 using type = decltype(std::declval<T>() * std::declval<U>());
395 };
396
397} // namespace internal
398
399
400
447template <typename T, typename U>
449{
450 using type =
451 typename internal::ProductTypeImpl<std::decay_t<T>, std::decay_t<U>>::type;
452};
453
454namespace internal
455{
456 // Annoyingly, there is no std::complex<T>::operator*(U) for scalars U
457 // other than T (not even in C++11, or C++14). We provide our own overloads
458 // in base/complex_overloads.h, but in order for them to work, we have to
459 // manually specify all products we want to allow:
460
461 template <typename T>
462 struct ProductTypeImpl<std::complex<T>, std::complex<T>>
463 {
464 using type = std::complex<T>;
465 };
466
467 template <typename T, typename U>
468 struct ProductTypeImpl<std::complex<T>, std::complex<U>>
469 {
470 using type = std::complex<typename ProductType<T, U>::type>;
471 };
472
473 template <typename U>
474 struct ProductTypeImpl<double, std::complex<U>>
475 {
476 using type = std::complex<typename ProductType<double, U>::type>;
477 };
478
479 template <typename T>
480 struct ProductTypeImpl<std::complex<T>, double>
481 {
482 using type = std::complex<typename ProductType<T, double>::type>;
483 };
484
485 template <typename U>
486 struct ProductTypeImpl<float, std::complex<U>>
487 {
488 using type = std::complex<typename ProductType<float, U>::type>;
489 };
490
491 template <typename T>
492 struct ProductTypeImpl<std::complex<T>, float>
493 {
494 using type = std::complex<typename ProductType<T, float>::type>;
495 };
496
497} // namespace internal
498
499
500
556template <typename T>
558
559
560template <>
561struct EnableIfScalar<double>
562{
563 using type = double;
564};
565
566template <>
567struct EnableIfScalar<float>
568{
569 using type = float;
570};
571
572template <>
573struct EnableIfScalar<long double>
574{
575 using type = long double;
576};
577
578template <>
580{
581 using type = int;
582};
583
584template <>
585struct EnableIfScalar<unsigned int>
586{
587 using type = unsigned int;
588};
589
590template <typename T>
591struct EnableIfScalar<std::complex<T>>
592{
593 using type = std::complex<T>;
594};
595
596
597// Forward declarations of vector types
598template <typename Number>
599class Vector;
600
601template <typename Number>
602class BlockVector;
603
605{
606 template <typename Number>
607 class ReadWriteVector;
608
609 namespace distributed
610 {
611 template <typename Number, typename MemorySpace>
612 class Vector;
613
614 template <typename Number, typename MemorySpace>
615 class BlockVector;
616 } // namespace distributed
617} // namespace LinearAlgebra
618
619#ifdef DEAL_II_WITH_PETSC
621{
622 class VectorBase;
623 class Vector;
624 class BlockVector;
625
626 namespace MPI
627 {
628 class Vector;
629 class BlockVector;
630
631 class SparseMatrix;
632 class BlockSparseMatrix;
633 } // namespace MPI
634} // namespace PETScWrappers
635#endif
636
637#ifdef DEAL_II_WITH_TRILINOS
638# if defined(DEAL_II_TRILINOS_WITH_EPETRA)
640{
641 namespace MPI
642 {
643 class Vector;
644 class BlockVector;
645 } // namespace MPI
646} // namespace TrilinosWrappers
647
648namespace LinearAlgebra
649{
650 namespace EpetraWrappers
651 {
652 class Vector;
653 }
654} // namespace LinearAlgebra
655# endif
656
657# ifdef DEAL_II_TRILINOS_WITH_TPETRA
658namespace LinearAlgebra
659{
660 namespace TpetraWrappers
661 {
662 template <typename Number, typename MemorySpace>
663 class Vector;
664
665 template <typename Number, typename MemorySpace>
666 class BlockVector;
667 } // namespace TpetraWrappers
668} // namespace LinearAlgebra
669# endif
670#endif
671
672
673
678namespace concepts
679{
680#if defined(DEAL_II_HAVE_CXX20) || defined(DOXYGEN)
691 template <typename C>
692 concept is_contiguous_container = requires(C &c) {
693 {
694 std::data(c)
695 };
696 {
697 std::size(c)
698 };
699 };
700
701
711 template <int dim, int spacedim>
713 (dim >= 1 && spacedim <= 3 && dim <= spacedim);
714
715 namespace internal
716 {
723 template <typename T>
724 inline constexpr bool is_dealii_vector_type = false;
725
726 template <typename Number>
727 inline constexpr bool is_dealii_vector_type<::Vector<Number>> = true;
728
729 template <typename Number>
730 inline constexpr bool is_dealii_vector_type<::BlockVector<Number>> =
731 true;
732
733 template <typename Number>
734 inline constexpr bool
736 true;
737
738 template <typename Number, typename MemorySpace>
739 inline constexpr bool is_dealii_vector_type<
741
742 template <typename Number, typename MemorySpace>
743 inline constexpr bool is_dealii_vector_type<
745 true;
746
747# ifdef DEAL_II_WITH_PETSC
748 template <>
750 true;
751
752 template <>
753 inline constexpr bool
755
756 template <>
757 inline constexpr bool
759
760 template <>
761 inline constexpr bool
763# endif
764
765# ifdef DEAL_II_WITH_TRILINOS
766# if defined(DEAL_II_TRILINOS_WITH_EPETRA)
767 template <>
768 inline constexpr bool
770
771 template <>
772 inline constexpr bool
774
775 template <>
776 inline constexpr bool
778 true;
779# endif
780
781# ifdef DEAL_II_TRILINOS_WITH_TPETRA
782 template <typename Number, typename MemorySpace>
783 inline constexpr bool is_dealii_vector_type<
785 true;
786
787 template <typename Number, typename MemorySpace>
788 inline constexpr bool is_dealii_vector_type<
790 true;
791# endif
792# endif
793
794
802 template <typename T>
803 inline constexpr bool is_dealii_petsc_vector_type = false;
804
805# ifdef DEAL_II_WITH_PETSC
806 template <>
807 inline constexpr bool
809
810 template <>
811 inline constexpr bool
813
814 template <>
815 inline constexpr bool
817
818 template <>
819 inline constexpr bool
821
822 template <>
823 inline constexpr bool
825 true;
826# endif
827
828
836 template <typename T>
837 inline constexpr bool is_dealii_petsc_matrix_type = false;
838
839# ifdef DEAL_II_WITH_PETSC
840 template <>
841 inline constexpr bool
843 true;
844
845 template <>
846 inline constexpr bool is_dealii_petsc_matrix_type<
848# endif
849 } // namespace internal
850
851
863 template <typename VectorType>
865 internal::is_dealii_vector_type<std::remove_cv_t<VectorType>>;
866
876 template <typename VectorType>
878 is_dealii_vector_type<VectorType> && (std::is_const_v<VectorType> == false);
879
888 template <typename VectorType>
890 internal::is_dealii_petsc_vector_type<VectorType>;
891
900 template <typename VectorType>
902 internal::is_dealii_petsc_matrix_type<VectorType>;
903#endif
904} // namespace concepts
905
906
907template <int dim, int spacedim>
909class Triangulation;
910
911template <int dim, int spacedim>
913class DoFHandler;
914
915namespace parallel
916{
917 namespace distributed
918 {
919 template <int dim, int spacedim>
921 class Triangulation;
922 }
923 namespace shared
924 {
925 template <int dim, int spacedim>
927 class Triangulation;
928 }
929 namespace fullydistributed
930 {
931 template <int dim, int spacedim>
933 class Triangulation;
934 }
935} // namespace parallel
936
937namespace concepts
938{
939 namespace internal
940 {
948 template <class T>
949 inline constexpr bool is_distributed_vector_type = false;
950
951 // ---- deal.II LA distributed vectors ----
952 template <typename Number, typename MemorySpace>
953 inline constexpr bool is_distributed_vector_type<
955
956 template <typename Number, typename MemorySpace>
957 inline constexpr bool is_distributed_vector_type<
959 true;
960
961#ifdef DEAL_II_TRILINOS_WITH_EPETRA
962 template <>
963 inline constexpr bool
964 is_distributed_vector_type<::TrilinosWrappers::MPI::Vector> = true;
965
966 template <>
967 inline constexpr bool
968 is_distributed_vector_type<::TrilinosWrappers::MPI::BlockVector> =
969 true;
970#endif
971
972#ifdef DEAL_II_WITH_PETSC
973 template <>
974 inline constexpr bool
975 is_distributed_vector_type<::PETScWrappers::MPI::Vector> = true;
976
977 template <>
978 inline constexpr bool
979 is_distributed_vector_type<::PETScWrappers::MPI::BlockVector> =
980 true;
981#endif
982 } // namespace internal
983
984#if defined(DEAL_II_HAVE_CXX20) || defined(DOXYGEN)
985 namespace internal
986 {
987 template <typename T>
988 inline constexpr bool is_triangulation_or_dof_handler = false;
989
990 template <int dim, int spacedim>
991 inline constexpr bool
993
994 template <int dim, int spacedim>
995 inline constexpr bool is_triangulation_or_dof_handler<
997
998 template <int dim, int spacedim>
999 inline constexpr bool is_triangulation_or_dof_handler<
1001
1002 template <int dim, int spacedim>
1003 inline constexpr bool is_triangulation_or_dof_handler<
1005
1006 template <int dim, int spacedim>
1007 inline constexpr bool
1009 } // namespace internal
1010
1011
1019 template <typename MeshType>
1021 internal::is_triangulation_or_dof_handler<MeshType>;
1022
1029 template <typename VectorType>
1030 concept is_vector_space_vector = requires(VectorType U,
1031 VectorType V,
1032 VectorType W,
1033 typename VectorType::value_type a,
1034 typename VectorType::value_type b,
1035 typename VectorType::value_type s,
1036 VectorOperation::values operation) {
1037 // Check local type requirements:
1038 typename VectorType::value_type;
1039 typename VectorType::size_type;
1040 typename VectorType::real_type;
1041
1042 // Check some assignment and reinit operations;
1043 U.reinit(V);
1044 U.reinit(V, /* omit_zeroing_entries= */ true);
1045
1046 U = V;
1047 U = a; // assignment of scalar
1048
1049 U.equ(a, V);
1050
1051 // Check scaling operations
1052 U *= a;
1053 U /= a;
1054
1055 U.scale(V);
1056
1057 // Vector additions:
1058 U += V;
1059 U -= V;
1060
1061 U.add(a);
1062 U.add(a, V);
1063 U.add(a, V, b, W);
1064
1065 U.sadd(s, a, V);
1066
1067 // Norms and similar stuff:
1068 {
1069 U.mean_value()
1070 } -> std::convertible_to<typename VectorType::value_type>;
1071
1072 {
1073 U.l1_norm()
1074 } -> std::convertible_to<typename VectorType::real_type>;
1075
1076 {
1077 U.l2_norm()
1078 } -> std::convertible_to<typename VectorType::real_type>;
1079
1080 {
1081 U.linfty_norm()
1082 } -> std::convertible_to<typename VectorType::real_type>;
1083
1084 // Dot products:
1085 {
1086 U *V
1087 } -> std::convertible_to<typename VectorType::value_type>;
1088
1089 {
1090 U.add_and_dot(a, V, W)
1091 } -> std::convertible_to<typename VectorType::value_type>;
1092
1093 // Some queries:
1094 {
1095 U.size()
1096 } -> std::convertible_to<typename VectorType::size_type>;
1097
1098 {
1099 U.all_zero()
1100 } -> std::same_as<bool>;
1101
1102 {
1103 U.get_mpi_communicator()
1104 } -> std::same_as<MPI_Comm>;
1105
1106 // Synchronization:
1107 {
1108 U.compress(operation)
1109 } -> std::same_as<void>;
1110 };
1111
1112
1121 template <typename MatrixType, typename VectorType>
1123 requires(const MatrixType &A, VectorType &dst, const VectorType &src) {
1124 A.vmult(dst, src);
1125 };
1126
1127
1136 template <typename MatrixType, typename VectorType>
1138 requires(const MatrixType &A, VectorType &dst, const VectorType &src) {
1139 A.Tvmult(dst, src);
1140 };
1141
1142#endif
1143
1144} // namespace concepts
1145
1146
1147
1149
1150#endif
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:249
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
constexpr bool is_distributed_vector_type
typename detected_or< Default, Op, Args... >::type detected_or_t
std::is_convertible< detected_t< Op, Args... >, To > is_detected_convertible
typename detected_or< nonesuch, Op, Args... >::value_t is_detected
typename detected_or< nonesuch, Op, Args... >::type detected_t
std::is_same< Expected, detected_t< Op, Args... > > is_detected_exact
constexpr bool is_supported_operation
STL namespace.
static bool equal(const T *p1, const T *p2)
static bool equal(const T *, const U *)
typename internal::ProductTypeImpl< std::decay_t< T >, std::decay_t< U > >::type type
static constexpr bool value
ValueType operator()(const ArgType &)
std::complex< typename ProductType< double, U >::type > type
std::complex< typename ProductType< float, U >::type > type
std::complex< typename ProductType< T, double >::type > type
std::complex< typename ProductType< T, float >::type > type
std::complex< typename ProductType< T, U >::type > type
decltype(std::declval< T >() *std::declval< U >()) type
void operator=(const nonesuch &)=delete
nonesuch(const nonesuch &)=delete
static constexpr bool value
static constexpr bool value
typename enable_if_all< Values... >::type enable_if_all_t
decltype(std::begin(std::declval< T >()), std::end(std::declval< T >())) begin_and_end_t
constexpr bool has_begin_and_end