deal.II version GIT relicensing-6430-g548498e238 2026-07-14 12:30: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
25
26#include <complex>
27#include <type_traits>
28#include <utility>
29
30
32
33// Detection idiom adapted from Version 2 of the C++ Extensions for Library
34// Fundamentals, ISO/IEC TS 19568:2017
35namespace internal
36{
42 namespace SupportsOperation
43 {
44 template <class...>
45 using void_t = void;
46
53 template <class Default,
54 class AlwaysVoid,
55 template <class...>
56 class Op,
57 class... Args>
58 struct detector
59 {
60 using value_t = std::false_type;
61 using type = Default;
62 };
63
76 template <class Default, template <class...> class Op, class... Args>
77 struct detector<Default, void_t<Op<Args...>>, Op, Args...>
78 {
79 using value_t = std::true_type;
80 using type = Op<Args...>;
81 };
82
83
89 {};
90
95 struct nonesuch : private nonesuch_base
96 {
97 ~nonesuch() = delete;
98 nonesuch(const nonesuch &) = delete;
99 void
100 operator=(const nonesuch &) = delete;
101 };
102
103 template <class Default, template <class...> class Op, class... Args>
104 using detected_or = detector<Default, void, Op, Args...>;
105
106 template <template <class...> class Op, class... Args>
107 using is_detected = typename detected_or<nonesuch, Op, Args...>::value_t;
108
109 template <template <class...> class Op, class... Args>
110 using detected_t = typename detected_or<nonesuch, Op, Args...>::type;
111
112 template <class Default, template <class...> class Op, class... Args>
113 using detected_or_t = typename detected_or<Default, Op, Args...>::type;
114
115 template <class Expected, template <class...> class Op, class... Args>
116 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
117
118 template <class To, template <class...> class Op, class... Args>
120 std::is_convertible<detected_t<Op, Args...>, To>;
121 } // namespace SupportsOperation
122
123
158 template <template <class...> class Op, class... Args>
159 constexpr bool is_supported_operation =
161} // namespace internal
162
163
164
165namespace internal
166{
167 namespace TemplateConstraints
168 {
177 template <bool... Values>
178 struct all_true
179 {
180 static constexpr bool value = (Values && ...);
181 };
182
183
188 template <bool... Values>
189 struct any_true
190 {
191 static constexpr bool value = (Values || ...);
192 };
193 } // namespace TemplateConstraints
194} // namespace internal
195
202template <class Base, class... Derived>
204{
206 std::is_base_of_v<Base, Derived>...>::value;
207};
208
209
210
217template <typename Type, class... Types>
219{
221 std::is_same_v<Type, Types>...>::value;
222};
223
224
225
232template <typename Type, class... Types>
234{
236 std::is_same_v<Type, Types>...>::value;
237};
238
239
240
241/*
242 * A generalization of `std::enable_if` that only works if
243 * <i>all</i> of the given boolean template parameters are
244 * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
245 * for what `std::enable_if` does.
246 *
247 * @note
248 * In contrast to `std::enable_if`, this template has no additional
249 * template type (which for `std::enable_if` is defaulted to `void`).
250 * As a consequence, this structure cannot be used for anything other
251 * than enabling or disabling a template declaration; in particular
252 * it cannot be used to set the return type of a function as one might
253 * do with something like
254 * @code
255 * template <typename T>
256 * typename std::enable_if<std::is_floating_point_v<T>, T>::type
257 * abs (const T t);
258 * @endcode
259 * which declares a function template `abs()` that can only be
260 * instantiated if `T` is a floating point type; this function then
261 * returns an object of type `T` as indicated by the last argument to
262 * `std::enable_if`. The reason `enable_if_all` does not allow providing
263 * this additional type is that variadic templates (here, the list of
264 * `bool` arguments) must be the last template argument.
265 */
266template <bool... Values>
268 : std::enable_if<internal::TemplateConstraints::all_true<Values...>::value>
269{};
270
271
272
273/*
274 * A generalization of `std::enable_if_t` that only works if
275 * <i>all</i> of the given boolean template parameters are
276 * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
277 * for what `std::enable_if_t` does.
278 *
279 * @note
280 * In contrast to `std::enable_if_t`, this template has no additional
281 * template type (which for `std::enable_if` is defaulted to `void`).
282 * As a consequence, this structure cannot be used for anything other
283 * than enabling or disabling a template declaration; in particular
284 * it cannot be used to set the return type of a function as one might
285 * do with something like
286 * @code
287 * template <typename T>
288 * std::enable_if_t<std::is_floating_point_v<T>, T>
289 * abs (const T t);
290 * @endcode
291 * which declares a function template `abs()` that can only be
292 * instantiated if `T` is a floating point type; this function then
293 * returns an object of type `T` as indicated by the last argument to
294 * `std::enable_if`. The reason `enable_if_all` does not allow providing
295 * this additional type is that variadic templates (here, the list of
296 * `bool` arguments) must be the last template argument.
297 */
298template <bool... Values>
299using enable_if_all_t = typename enable_if_all<Values...>::type;
300
301
307template <typename T>
309 decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()));
310
311template <typename T>
312constexpr bool has_begin_and_end =
313 internal::is_supported_operation<begin_and_end_t, T>;
314
315
321template <typename ArgType, typename ValueType>
323{
324 ValueType value;
325 ValueType
326 operator()(const ArgType &)
327 {
328 return value;
329 }
330};
331
332
333
351{
356 template <typename T>
357 static bool
358 equal(const T *p1, const T *p2)
359 {
360 return (p1 == p2);
361 }
362
363
370 template <typename T, typename U>
371 static bool
372 equal(const T *, const U *)
373 {
374 return false;
375 }
376};
377
378
379
380namespace internal
381{
392 template <typename T, typename U>
394 {
395 using type = decltype(std::declval<T>() * std::declval<U>());
396 };
397
398} // namespace internal
399
400
401
448template <typename T, typename U>
450{
451 using type =
452 typename internal::ProductTypeImpl<std::decay_t<T>, std::decay_t<U>>::type;
453};
454
455namespace internal
456{
457 // Annoyingly, there is no std::complex<T>::operator*(U) for scalars U
458 // other than T (not even in C++11, or C++14). We provide our own overloads
459 // in base/complex_overloads.h, but in order for them to work, we have to
460 // manually specify all products we want to allow:
461
462 template <typename T>
463 struct ProductTypeImpl<std::complex<T>, std::complex<T>>
464 {
465 using type = std::complex<T>;
466 };
467
468 template <typename T, typename U>
469 struct ProductTypeImpl<std::complex<T>, std::complex<U>>
470 {
471 using type = std::complex<typename ProductType<T, U>::type>;
472 };
473
474 template <typename U>
475 struct ProductTypeImpl<double, std::complex<U>>
476 {
477 using type = std::complex<typename ProductType<double, U>::type>;
478 };
479
480 template <typename T>
481 struct ProductTypeImpl<std::complex<T>, double>
482 {
483 using type = std::complex<typename ProductType<T, double>::type>;
484 };
485
486 template <typename U>
487 struct ProductTypeImpl<float, std::complex<U>>
488 {
489 using type = std::complex<typename ProductType<float, U>::type>;
490 };
491
492 template <typename T>
493 struct ProductTypeImpl<std::complex<T>, float>
494 {
495 using type = std::complex<typename ProductType<T, float>::type>;
496 };
497
498} // namespace internal
499
500
501
557template <typename T>
559
560
561template <>
562struct EnableIfScalar<double>
563{
564 using type = double;
565};
566
567template <>
568struct EnableIfScalar<float>
569{
570 using type = float;
571};
572
573template <>
574struct EnableIfScalar<long double>
575{
576 using type = long double;
577};
578
579template <>
581{
582 using type = int;
583};
584
585template <>
586struct EnableIfScalar<unsigned int>
587{
588 using type = unsigned int;
589};
590
591template <typename T>
592struct EnableIfScalar<std::complex<T>>
593{
594 using type = std::complex<T>;
595};
596
597
598// Forward declarations of vector types
599template <typename Number>
600class Vector;
601
602template <typename Number>
603class BlockVector;
604
606{
607 template <typename Number>
608 class ReadWriteVector;
609
610 namespace distributed
611 {
612 template <typename Number, typename MemorySpace>
613 class Vector;
614
615 template <typename Number, typename MemorySpace>
616 class BlockVector;
617 } // namespace distributed
618} // namespace LinearAlgebra
619
620#ifdef DEAL_II_WITH_PETSC
622{
623 class VectorBase;
624 class Vector;
625 class BlockVector;
626
627 namespace MPI
628 {
629 class Vector;
630 class BlockVector;
631
632 class SparseMatrix;
633 class BlockSparseMatrix;
634 } // namespace MPI
635} // namespace PETScWrappers
636#endif
637
638#ifdef DEAL_II_WITH_TRILINOS
639# if defined(DEAL_II_TRILINOS_WITH_EPETRA)
640namespace LinearAlgebra
641{
642 namespace EpetraWrappers
643 {
644 class Vector;
645 }
646} // namespace LinearAlgebra
647# endif
648#endif
649
650
651
656namespace concepts
657{
658#if defined(DEAL_II_HAVE_CXX20) || defined(DOXYGEN)
669 template <typename C>
670 concept is_contiguous_container = requires(C &c) {
671 {
672 std::data(c)
673 };
674 {
675 std::size(c)
676 };
677 };
678
679
689 template <int dim, int spacedim>
691 (dim >= 1 && spacedim <= 3 && dim <= spacedim);
692
693 namespace internal
694 {
701 template <typename T>
702 inline constexpr bool is_dealii_vector_type = false;
703
704 template <typename Number>
705 inline constexpr bool is_dealii_vector_type<::Vector<Number>> = true;
706
707 template <typename Number>
708 inline constexpr bool is_dealii_vector_type<::BlockVector<Number>> =
709 true;
710
711 template <typename Number>
712 inline constexpr bool
714 true;
715
716 template <typename Number, typename MemorySpace>
717 inline constexpr bool is_dealii_vector_type<
719
720 template <typename Number, typename MemorySpace>
721 inline constexpr bool is_dealii_vector_type<
723 true;
724
725# ifdef DEAL_II_WITH_PETSC
726 template <>
728 true;
729
730 template <>
731 inline constexpr bool
733
734 template <>
735 inline constexpr bool
737
738 template <>
739 inline constexpr bool
741# endif
742
743# ifdef DEAL_II_WITH_TRILINOS
744# if defined(DEAL_II_TRILINOS_WITH_EPETRA)
745 template <>
746 inline constexpr bool
748
749 template <>
750 inline constexpr bool
752
753 template <>
754 inline constexpr bool
756 true;
757# endif
758
759# ifdef DEAL_II_TRILINOS_WITH_TPETRA
760 template <typename Number, typename MemorySpace>
761 inline constexpr bool is_dealii_vector_type<
763 true;
764
765 template <typename Number, typename MemorySpace>
766 inline constexpr bool is_dealii_vector_type<
768 true;
769# endif
770# endif
771
772
780 template <typename T>
781 inline constexpr bool is_dealii_petsc_vector_type = false;
782
783# ifdef DEAL_II_WITH_PETSC
784 template <>
785 inline constexpr bool
787
788 template <>
789 inline constexpr bool
791
792 template <>
793 inline constexpr bool
795
796 template <>
797 inline constexpr bool
799
800 template <>
801 inline constexpr bool
803 true;
804# endif
805
806
814 template <typename T>
815 inline constexpr bool is_dealii_petsc_matrix_type = false;
816
817# ifdef DEAL_II_WITH_PETSC
818 template <>
819 inline constexpr bool
821 true;
822
823 template <>
824 inline constexpr bool is_dealii_petsc_matrix_type<
826# endif
827 } // namespace internal
828
829
841 template <typename VectorType>
843 internal::is_dealii_vector_type<std::remove_cv_t<VectorType>>;
844
854 template <typename VectorType>
856 is_dealii_vector_type<VectorType> && (std::is_const_v<VectorType> == false);
857
866 template <typename VectorType>
868 internal::is_dealii_petsc_vector_type<VectorType>;
869
878 template <typename VectorType>
880 internal::is_dealii_petsc_matrix_type<VectorType>;
881#endif
882} // namespace concepts
883
884
885template <int dim, int spacedim>
887class Triangulation;
888
889template <int dim, int spacedim>
891class DoFHandler;
892
893namespace parallel
894{
895 namespace distributed
896 {
897 template <int dim, int spacedim>
899 class Triangulation;
900 }
901 namespace shared
902 {
903 template <int dim, int spacedim>
905 class Triangulation;
906 }
907 namespace fullydistributed
908 {
909 template <int dim, int spacedim>
911 class Triangulation;
912 }
913} // namespace parallel
914
915namespace concepts
916{
917 namespace internal
918 {
926 template <class T>
927 inline constexpr bool is_distributed_vector_type = false;
928
929 // ---- deal.II LA distributed vectors ----
930 template <typename Number, typename MemorySpace>
931 inline constexpr bool is_distributed_vector_type<
933
934 template <typename Number, typename MemorySpace>
935 inline constexpr bool is_distributed_vector_type<
937 true;
938
939#ifdef DEAL_II_TRILINOS_WITH_EPETRA
940 template <>
941 inline constexpr bool
942 is_distributed_vector_type<::TrilinosWrappers::MPI::Vector> = true;
943
944 template <>
945 inline constexpr bool
946 is_distributed_vector_type<::TrilinosWrappers::MPI::BlockVector> =
947 true;
948#endif
949
950#ifdef DEAL_II_WITH_PETSC
951 template <>
952 inline constexpr bool
953 is_distributed_vector_type<::PETScWrappers::MPI::Vector> = true;
954
955 template <>
956 inline constexpr bool
957 is_distributed_vector_type<::PETScWrappers::MPI::BlockVector> =
958 true;
959#endif
960 } // namespace internal
961
962#if defined(DEAL_II_HAVE_CXX20) || defined(DOXYGEN)
963 namespace internal
964 {
965 template <typename T>
966 inline constexpr bool is_triangulation_or_dof_handler = false;
967
968 template <int dim, int spacedim>
969 inline constexpr bool
971
972 template <int dim, int spacedim>
973 inline constexpr bool is_triangulation_or_dof_handler<
975
976 template <int dim, int spacedim>
977 inline constexpr bool is_triangulation_or_dof_handler<
979
980 template <int dim, int spacedim>
981 inline constexpr bool is_triangulation_or_dof_handler<
983
984 template <int dim, int spacedim>
985 inline constexpr bool
987 } // namespace internal
988
989
997 template <typename MeshType>
999 internal::is_triangulation_or_dof_handler<MeshType>;
1000
1007 template <typename VectorType>
1008 concept is_vector_space_vector = requires(VectorType U,
1009 VectorType V,
1010 VectorType W,
1011 typename VectorType::value_type a,
1012 typename VectorType::value_type b,
1013 typename VectorType::value_type s,
1014 VectorOperation::values operation) {
1015 // Check local type requirements:
1016 typename VectorType::value_type;
1017 typename VectorType::size_type;
1018 typename VectorType::real_type;
1019
1020 // Check some assignment and reinit operations;
1021 U.reinit(V);
1022 U.reinit(V, /* omit_zeroing_entries= */ true);
1023
1024 U = V;
1025 U = a; // assignment of scalar
1026
1027 U.equ(a, V);
1028
1029 // Check scaling operations
1030 U *= a;
1031 U /= a;
1032
1033 U.scale(V);
1034
1035 // Vector additions:
1036 U += V;
1037 U -= V;
1038
1039 U.add(a);
1040 U.add(a, V);
1041 U.add(a, V, b, W);
1042
1043 U.sadd(s, a, V);
1044
1045 // Norms and similar stuff:
1046 {
1047 U.mean_value()
1048 } -> std::convertible_to<typename VectorType::value_type>;
1049
1050 {
1051 U.l1_norm()
1052 } -> std::convertible_to<typename VectorType::real_type>;
1053
1054 {
1055 U.l2_norm()
1056 } -> std::convertible_to<typename VectorType::real_type>;
1057
1058 {
1059 U.linfty_norm()
1060 } -> std::convertible_to<typename VectorType::real_type>;
1061
1062 // Dot products:
1063 {
1064 U *V
1065 } -> std::convertible_to<typename VectorType::value_type>;
1066
1067 {
1068 U.add_and_dot(a, V, W)
1069 } -> std::convertible_to<typename VectorType::value_type>;
1070
1071 // Some queries:
1072 {
1073 U.size()
1074 } -> std::convertible_to<typename VectorType::size_type>;
1075
1076 {
1077 U.all_zero()
1078 } -> std::same_as<bool>;
1079
1080 {
1081 U.get_mpi_communicator()
1082 } -> std::same_as<MPI_Comm>;
1083
1084 // Synchronization:
1085 {
1086 U.compress(operation)
1087 } -> std::same_as<void>;
1088 };
1089
1090
1099 template <typename MatrixType, typename VectorType>
1101 requires(const MatrixType &A, VectorType &dst, const VectorType &src) {
1102 A.vmult(dst, src);
1103 };
1104
1105
1114 template <typename MatrixType, typename VectorType>
1116 requires(const MatrixType &A, VectorType &dst, const VectorType &src) {
1117 A.Tvmult(dst, src);
1118 };
1119
1120#endif
1121
1122} // namespace concepts
1123
1124
1125
1127
1128#endif
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:248
#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