Reference documentation for deal.II version GIT 6dd81a2340 2022-11-29 05:55:02+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 
23 
24 #include <complex>
25 #include <utility>
26 
28 
29 // Detection idiom adapted from Version 2 of the C++ Extensions for Library
30 // Fundamentals, ISO/IEC TS 19568:2017
31 namespace internal
32 {
38  namespace SupportsOperation
39  {
40  template <class...>
41  using void_t = void;
42 
49  template <class Default,
50  class AlwaysVoid,
51  template <class...>
52  class Op,
53  class... Args>
54  struct detector
55  {
56  using value_t = std::false_type;
57  using type = Default;
58  };
59 
72  template <class Default, template <class...> class Op, class... Args>
73  struct detector<Default, void_t<Op<Args...>>, Op, Args...>
74  {
75  using value_t = std::true_type;
76  using type = Op<Args...>;
77  };
78 
79 
85  {};
86 
91  struct nonesuch : private nonesuch_base
92  {
93  ~nonesuch() = delete;
94  nonesuch(nonesuch const &) = delete;
95  void
96  operator=(nonesuch const &) = delete;
97  };
98 
99  template <class Default, template <class...> class Op, class... Args>
100  using detected_or = detector<Default, void, Op, Args...>;
101 
102  template <template <class...> class Op, class... Args>
103  using is_detected = typename detected_or<nonesuch, Op, Args...>::value_t;
104 
105  template <template <class...> class Op, class... Args>
106  using detected_t = typename detected_or<nonesuch, Op, Args...>::type;
107 
108  template <class Default, template <class...> class Op, class... Args>
109  using detected_or_t = typename detected_or<Default, Op, Args...>::type;
110 
111  template <class Expected, template <class...> class Op, class... Args>
112  using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
113 
114  template <class To, template <class...> class Op, class... Args>
116  std::is_convertible<detected_t<Op, Args...>, To>;
117  } // namespace SupportsOperation
118 
119 
154  template <template <class...> class Op, class... Args>
155  constexpr bool is_supported_operation =
156  SupportsOperation::is_detected<Op, Args...>::value;
157 } // namespace internal
158 
159 
160 
161 namespace internal
162 {
163  namespace TemplateConstraints
164  {
165  // TODO: Once we are able to use DEAL_II_HAVE_CXX17, the following classes
166  // can be made much simpler with the help of fold expressions, see
167  // https://en.cppreference.com/w/cpp/language/fold
168 
169  // helper struct for is_base_of_all and all_same_as
170  template <bool... Values>
171  struct BoolStorage;
172 
173 
182  template <bool... Values>
183  struct all_true
184  {
185  static constexpr bool value =
186  std::is_same<BoolStorage<Values..., true>,
187  BoolStorage<true, Values...>>::value;
188  };
189 
190 
195  template <bool... Values>
196  struct any_true;
197 
198 
199  template <bool V1, bool... Values>
200  struct any_true<V1, Values...>
201  {
202  static constexpr bool value = V1 || any_true<Values...>::value;
203  };
204 
205 
206  template <>
207  struct any_true<>
208  {
209  static constexpr bool value = false;
210  };
211  } // namespace TemplateConstraints
212 } // namespace internal
213 
220 template <class Base, class... Derived>
222 {
224  std::is_base_of<Base, Derived>::value...>::value;
225 };
226 
227 
228 
235 template <class Type, class... Types>
237 {
239  std::is_same<Type, Types>::value...>::value;
240 };
241 
242 
243 
250 template <class Type, class... Types>
252 {
254  std::is_same<Type, Types>::value...>::value;
255 };
256 
257 
258 
259 /*
260  * A generalization of `std::enable_if` that only works if
261  * <i>all</i> of the given boolean template parameters are
262  * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
263  * for what `std::enable_if` does.
264  *
265  * @note
266  * In contrast to `std::enable_if`, this template has no additional
267  * template type (which for `std::enable_if` is defaulted to `void`).
268  * As a consequence, this structure cannot be used for anything other
269  * than enabling or disabling a template declaration; in particular
270  * it cannot be used to set the return type of a function as one might
271  * do with something like
272  * @code
273  * template <typename T>
274  * typename std::enable_if<std::is_floating_point<T>::value, T>::type
275  * abs (const T t);
276  * @endcode
277  * which declares a function template `abs()` that can only be
278  * instantiated if `T` is a floating point type; this function then
279  * returns an object of type `T` as indicated by the last argument to
280  * `std::enable_if`. The reason `enable_if_all` does not allow providing
281  * this additional type is that variadic templates (here, the list of
282  * `bool` arguments) must be the last template argument.
283  */
284 template <bool... Values>
286  : std::enable_if<internal::TemplateConstraints::all_true<Values...>::value>
287 {};
288 
289 
290 
291 /*
292  * A generalization of `std::enable_if_t` that only works if
293  * <i>all</i> of the given boolean template parameters are
294  * true. See [here](https://en.cppreference.com/w/cpp/types/enable_if)
295  * for what `std::enable_if_t` does.
296  *
297  * @note
298  * In contrast to `std::enable_if_t`, this template has no additional
299  * template type (which for `std::enable_if` is defaulted to `void`).
300  * As a consequence, this structure cannot be used for anything other
301  * than enabling or disabling a template declaration; in particular
302  * it cannot be used to set the return type of a function as one might
303  * do with something like
304  * @code
305  * template <typename T>
306  * std::enable_if_t<std::is_floating_point<T>::value, T>
307  * abs (const T t);
308  * @endcode
309  * which declares a function template `abs()` that can only be
310  * instantiated if `T` is a floating point type; this function then
311  * returns an object of type `T` as indicated by the last argument to
312  * `std::enable_if`. The reason `enable_if_all` does not allow providing
313  * this additional type is that variadic templates (here, the list of
314  * `bool` arguments) must be the last template argument.
315  */
316 template <bool... Values>
317 using enable_if_all_t = typename enable_if_all<Values...>::type;
318 
319 
325 template <typename T>
327  decltype(std::begin(std::declval<T>()), std::end(std::declval<T>()));
328 
329 template <typename T>
330 constexpr bool has_begin_and_end =
331  internal::is_supported_operation<begin_and_end_t, T>;
332 
333 
334 
392 template <typename T>
393 struct identity
394 {
395  using type = T;
396 };
397 
398 
399 
405 template <typename ArgType, typename ValueType>
407 {
408  ValueType value;
409  ValueType
410  operator()(const ArgType &)
411  {
412  return value;
413  }
414 };
415 
416 
417 
435 {
440  template <typename T>
441  static bool
442  equal(const T *p1, const T *p2)
443  {
444  return (p1 == p2);
445  }
446 
447 
454  template <typename T, typename U>
455  static bool
456  equal(const T *, const U *)
457  {
458  return false;
459  }
460 };
461 
462 
463 
464 namespace internal
465 {
476  template <typename T, typename U>
478  {
479  using type = decltype(std::declval<T>() * std::declval<U>());
480  };
481 
482 } // namespace internal
483 
484 
485 
532 template <typename T, typename U>
534 {
535  using type =
537  typename std::decay<U>::type>::type;
538 };
539 
540 namespace internal
541 {
542  // Annoyingly, there is no std::complex<T>::operator*(U) for scalars U
543  // other than T (not even in C++11, or C++14). We provide our own overloads
544  // in base/complex_overloads.h, but in order for them to work, we have to
545  // manually specify all products we want to allow:
546 
547  template <typename T>
548  struct ProductTypeImpl<std::complex<T>, std::complex<T>>
549  {
550  using type = std::complex<T>;
551  };
552 
553  template <typename T, typename U>
554  struct ProductTypeImpl<std::complex<T>, std::complex<U>>
555  {
556  using type = std::complex<typename ProductType<T, U>::type>;
557  };
558 
559  template <typename U>
560  struct ProductTypeImpl<double, std::complex<U>>
561  {
562  using type = std::complex<typename ProductType<double, U>::type>;
563  };
564 
565  template <typename T>
566  struct ProductTypeImpl<std::complex<T>, double>
567  {
568  using type = std::complex<typename ProductType<T, double>::type>;
569  };
570 
571  template <typename U>
572  struct ProductTypeImpl<float, std::complex<U>>
573  {
574  using type = std::complex<typename ProductType<float, U>::type>;
575  };
576 
577  template <typename T>
578  struct ProductTypeImpl<std::complex<T>, float>
579  {
580  using type = std::complex<typename ProductType<T, float>::type>;
581  };
582 
583 } // namespace internal
584 
585 
586 
642 template <typename T>
644 
645 
646 template <>
648 {
649  using type = double;
650 };
651 
652 template <>
653 struct EnableIfScalar<float>
654 {
655  using type = float;
656 };
657 
658 template <>
659 struct EnableIfScalar<long double>
660 {
661  using type = long double;
662 };
663 
664 template <>
665 struct EnableIfScalar<int>
666 {
667  using type = int;
668 };
669 
670 template <>
671 struct EnableIfScalar<unsigned int>
672 {
673  using type = unsigned int;
674 };
675 
676 template <typename T>
677 struct EnableIfScalar<std::complex<T>>
678 {
679  using type = std::complex<T>;
680 };
681 
682 
684 
685 #endif
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:458
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:459
static const char U
static const char T
VectorType::value_type * begin(VectorType &V)
VectorType::value_type * end(VectorType &V)
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