Reference documentation for deal.II version GIT 0980a66d4b 2023-03-23 20:20:03+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\}}\)
template_constraints.h
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2003 - 2022 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_template_constraints_h
17 #define dealii_template_constraints_h
18 
19 
20 #include <deal.II/base/config.h>
21 
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
34 namespace 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(nonesuch const &) = delete;
98  void
99  operator=(nonesuch const &) = 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 =
159  SupportsOperation::is_detected<Op, Args...>::value;
160 } // namespace internal
161 
162 
163 
164 namespace internal
165 {
166  namespace TemplateConstraints
167  {
168  // TODO: Once we are able to use DEAL_II_HAVE_CXX17, the following classes
169  // can be made much simpler with the help of fold expressions, see
170  // https://en.cppreference.com/w/cpp/language/fold
171 
172  // helper struct for is_base_of_all and all_same_as
173  template <bool... Values>
174  struct BoolStorage;
175 
176 
185  template <bool... Values>
186  struct all_true
187  {
188  static constexpr bool value =
189  std::is_same<BoolStorage<Values..., true>,
190  BoolStorage<true, Values...>>::value;
191  };
192 
193 
198  template <bool... Values>
199  struct any_true;
200 
201 
202  template <bool V1, bool... Values>
203  struct any_true<V1, Values...>
204  {
205  static constexpr bool value = V1 || any_true<Values...>::value;
206  };
207 
208 
209  template <>
210  struct any_true<>
211  {
212  static constexpr bool value = false;
213  };
214  } // namespace TemplateConstraints
215 } // namespace internal
216 
223 template <class Base, class... Derived>
225 {
227  std::is_base_of<Base, Derived>::value...>::value;
228 };
229 
230 
231 
238 template <class Type, class... Types>
240 {
242  std::is_same<Type, Types>::value...>::value;
243 };
244 
245 
246 
253 template <class Type, class... Types>
255 {
257  std::is_same<Type, Types>::value...>::value;
258 };
259 
260 
261 
262 /*
263  * A generalization of `std::enable_if` that only works if
264  * <i>all</i> of the given boolean template parameters are
265  * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
266  * for what `std::enable_if` does.
267  *
268  * @note
269  * In contrast to `std::enable_if`, this template has no additional
270  * template type (which for `std::enable_if` is defaulted to `void`).
271  * As a consequence, this structure cannot be used for anything other
272  * than enabling or disabling a template declaration; in particular
273  * it cannot be used to set the return type of a function as one might
274  * do with something like
275  * @code
276  * template <typename T>
277  * typename std::enable_if<std::is_floating_point<T>::value, T>::type
278  * abs (const T t);
279  * @endcode
280  * which declares a function template `abs()` that can only be
281  * instantiated if `T` is a floating point type; this function then
282  * returns an object of type `T` as indicated by the last argument to
283  * `std::enable_if`. The reason `enable_if_all` does not allow providing
284  * this additional type is that variadic templates (here, the list of
285  * `bool` arguments) must be the last template argument.
286  */
287 template <bool... Values>
289  : std::enable_if<internal::TemplateConstraints::all_true<Values...>::value>
290 {};
291 
292 
293 
294 /*
295  * A generalization of `std::enable_if_t` that only works if
296  * <i>all</i> of the given boolean template parameters are
297  * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
298  * for what `std::enable_if_t` does.
299  *
300  * @note
301  * In contrast to `std::enable_if_t`, this template has no additional
302  * template type (which for `std::enable_if` is defaulted to `void`).
303  * As a consequence, this structure cannot be used for anything other
304  * than enabling or disabling a template declaration; in particular
305  * it cannot be used to set the return type of a function as one might
306  * do with something like
307  * @code
308  * template <typename T>
309  * std::enable_if_t<std::is_floating_point<T>::value, T>
310  * abs (const T t);
311  * @endcode
312  * which declares a function template `abs()` that can only be
313  * instantiated if `T` is a floating point type; this function then
314  * returns an object of type `T` as indicated by the last argument to
315  * `std::enable_if`. The reason `enable_if_all` does not allow providing
316  * this additional type is that variadic templates (here, the list of
317  * `bool` arguments) must be the last template argument.
318  */
319 template <bool... Values>
320 using enable_if_all_t = typename enable_if_all<Values...>::type;
321 
322 
328 template <typename T>
330  decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()));
331 
332 template <typename T>
333 constexpr bool has_begin_and_end =
334  internal::is_supported_operation<begin_and_end_t, T>;
335 
336 
344 template <typename T>
346 
347 
353 template <typename ArgType, typename ValueType>
355 {
356  ValueType value;
357  ValueType
358  operator()(const ArgType &)
359  {
360  return value;
361  }
362 };
363 
364 
365 
383 {
388  template <typename T>
389  static bool
390  equal(const T *p1, const T *p2)
391  {
392  return (p1 == p2);
393  }
394 
395 
402  template <typename T, typename U>
403  static bool
404  equal(const T *, const U *)
405  {
406  return false;
407  }
408 };
409 
410 
411 
412 namespace internal
413 {
424  template <typename T, typename U>
426  {
427  using type = decltype(std::declval<T>() * std::declval<U>());
428  };
429 
430 } // namespace internal
431 
432 
433 
480 template <typename T, typename U>
482 {
483  using type =
485  typename std::decay<U>::type>::type;
486 };
487 
488 namespace internal
489 {
490  // Annoyingly, there is no std::complex<T>::operator*(U) for scalars U
491  // other than T (not even in C++11, or C++14). We provide our own overloads
492  // in base/complex_overloads.h, but in order for them to work, we have to
493  // manually specify all products we want to allow:
494 
495  template <typename T>
496  struct ProductTypeImpl<std::complex<T>, std::complex<T>>
497  {
498  using type = std::complex<T>;
499  };
500 
501  template <typename T, typename U>
502  struct ProductTypeImpl<std::complex<T>, std::complex<U>>
503  {
504  using type = std::complex<typename ProductType<T, U>::type>;
505  };
506 
507  template <typename U>
508  struct ProductTypeImpl<double, std::complex<U>>
509  {
510  using type = std::complex<typename ProductType<double, U>::type>;
511  };
512 
513  template <typename T>
514  struct ProductTypeImpl<std::complex<T>, double>
515  {
516  using type = std::complex<typename ProductType<T, double>::type>;
517  };
518 
519  template <typename U>
520  struct ProductTypeImpl<float, std::complex<U>>
521  {
522  using type = std::complex<typename ProductType<float, U>::type>;
523  };
524 
525  template <typename T>
526  struct ProductTypeImpl<std::complex<T>, float>
527  {
528  using type = std::complex<typename ProductType<T, float>::type>;
529  };
530 
531 } // namespace internal
532 
533 
534 
590 template <typename T>
592 
593 
594 template <>
596 {
597  using type = double;
598 };
599 
600 template <>
601 struct EnableIfScalar<float>
602 {
603  using type = float;
604 };
605 
606 template <>
607 struct EnableIfScalar<long double>
608 {
609  using type = long double;
610 };
611 
612 template <>
613 struct EnableIfScalar<int>
614 {
615  using type = int;
616 };
617 
618 template <>
619 struct EnableIfScalar<unsigned int>
620 {
621  using type = unsigned int;
622 };
623 
624 template <typename T>
625 struct EnableIfScalar<std::complex<T>>
626 {
627  using type = std::complex<T>;
628 };
629 
630 
631 // Forward declarations of vector types
632 template <typename Number>
633 class Vector;
634 
635 template <typename Number>
636 class BlockVector;
637 
638 namespace LinearAlgebra
639 {
640  template <typename Number>
641  class Vector;
642 
643  template <typename Number>
644  class BlockVector;
645 
646  namespace distributed
647  {
648  template <typename Number, typename MemorySpace>
649  class Vector;
650 
651  template <typename Number>
652  class BlockVector;
653  } // namespace distributed
654 } // namespace LinearAlgebra
655 
656 #ifdef DEAL_II_WITH_PETSC
657 namespace PETScWrappers
658 {
659  class Vector;
660  class BlockVector;
661 
662  namespace MPI
663  {
664  class Vector;
665  class BlockVector;
666  } // namespace MPI
667 } // namespace PETScWrappers
668 #endif
669 
670 #ifdef DEAL_II_WITH_TRILINOS
672 {
673  namespace MPI
674  {
675  class Vector;
676  class BlockVector;
677  } // namespace MPI
678 } // namespace TrilinosWrappers
679 
680 namespace LinearAlgebra
681 {
682  namespace EpetraWrappers
683  {
684  class Vector;
685  }
686 
687 # ifdef DEAL_II_TRILINOS_WITH_TPETRA
688  namespace TpetraWrappers
689  {
690  template <typename Number>
691  class Vector;
692  }
693 # endif
694 } // namespace LinearAlgebra
695 #endif
696 
697 
702 namespace concepts
703 {
704 #if defined(DEAL_II_HAVE_CXX20) || defined(DOXYGEN)
714  template <int dim, int spacedim>
715  concept is_valid_dim_spacedim = (dim >= 1 && spacedim <= 3 &&
716  dim <= spacedim);
717 
718  namespace internal
719  {
726  template <typename T>
727  inline constexpr bool is_dealii_vector_type = false;
728 
729  template <typename Number>
730  inline constexpr bool is_dealii_vector_type<::Vector<Number>> = true;
731 
732  template <typename Number>
733  inline constexpr bool is_dealii_vector_type<::BlockVector<Number>> =
734  true;
735 
736  template <typename Number>
737  inline constexpr bool
738  is_dealii_vector_type<::LinearAlgebra::Vector<Number>> = true;
739 
740  template <typename Number>
741  inline constexpr bool
742  is_dealii_vector_type<::LinearAlgebra::BlockVector<Number>> = true;
743 
744  template <typename Number, typename MemorySpace>
745  inline constexpr bool is_dealii_vector_type<
747 
748  template <typename Number>
749  inline constexpr bool is_dealii_vector_type<
751 
752 # ifdef DEAL_II_WITH_PETSC
753  template <>
754  inline constexpr bool is_dealii_vector_type<::PETScWrappers::Vector> =
755  true;
756 
757  template <>
758  inline constexpr bool
759  is_dealii_vector_type<::PETScWrappers::BlockVector> = true;
760 
761  template <>
762  inline constexpr bool
763  is_dealii_vector_type<::PETScWrappers::MPI::Vector> = true;
764 
765  template <>
766  inline constexpr bool
767  is_dealii_vector_type<::PETScWrappers::MPI::BlockVector> = true;
768 # endif
769 
770 # ifdef DEAL_II_WITH_TRILINOS
771  template <>
772  inline constexpr bool
773  is_dealii_vector_type<::TrilinosWrappers::MPI::Vector> = true;
774 
775  template <>
776  inline constexpr bool
777  is_dealii_vector_type<::TrilinosWrappers::MPI::BlockVector> = true;
778 
779  template <>
780  inline constexpr bool
781  is_dealii_vector_type<::LinearAlgebra::EpetraWrappers::Vector> =
782  true;
783 
784 # ifdef DEAL_II_TRILINOS_WITH_TPETRA
785  template <typename Number>
786  inline constexpr bool is_dealii_vector_type<
788 # endif
789 # endif
790  } // namespace internal
791 
792 
804  template <typename VectorType>
806  internal::is_dealii_vector_type<std::remove_cv_t<VectorType>>;
807 
817  template <typename VectorType>
818  concept is_writable_dealii_vector_type = is_dealii_vector_type<VectorType> &&
819  (std::is_const_v<VectorType> ==
820  false);
821 
822 #endif
823 } // namespace concepts
824 
825 
827 
828 #endif
Definition: vector.h:109
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:474
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:475
static const char U
static const char T
VectorType::value_type * begin(VectorType &V)
VectorType::value_type * end(VectorType &V)
constexpr bool is_dealii_vector_type
concept is_writable_dealii_vector_type
concept is_dealii_vector_type
concept is_valid_dim_spacedim
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
static bool equal(const T *p1, const T *p2)
static bool equal(const T *, const U *)
typename internal::ProductTypeImpl< typename std::decay< T >::type, typename std::decay< U >::type >::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
nonesuch(nonesuch const &)=delete
void operator=(nonesuch const &)=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