1 // --------------------------------------------------------------------- 2 // 3 // Copyright (C) 2003 - 2020 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 22 #include <deal.II/base/complex_overloads.h> 23 24 #include <complex> 25 #include <iterator> 26 #include <utility> 27 28 DEAL_II_NAMESPACE_OPEN 29 30 namespace internal 31 { 32 namespace TemplateConstraints 33 { 34 // helper struct for is_base_of_all and all_same_as 35 template <bool... Values> 36 struct BoolStorage; 37 38 39 /** 40 * A helper class whose `value` member is true or false depending on 41 * whether all of the given boolean template arguments are true. 42 */ 43 template <bool... Values> 44 struct all_true 45 { 46 static constexpr bool value = 47 std::is_same<BoolStorage<Values..., true>, 48 BoolStorage<true, Values...>>::value; 49 }; 50 } // namespace TemplateConstraints 51 } // namespace internal 52 53 /** 54 * This struct is a generalization of std::is_base_of<Base, Derived> 55 * to template parameter packs and tests if all of the Derived... 56 * classes have Base as base class or are Base itself. The result 57 * is stored in the member variable value. 58 */ 59 template <class Base, class... Derived> 60 struct is_base_of_all 61 { 62 static constexpr bool value = internal::TemplateConstraints::all_true< 63 std::is_base_of<Base, Derived>::value...>::value; 64 }; 65 66 67 68 /** 69 * This struct is a generalization of std::is_same to template 70 * parameter packs and tests if all of the types in the `Types...` 71 * parameter pack are equal to the `Type` given as first template 72 * argument. The result is stored in the member variable value. 73 */ 74 template <class Type, class... Types> 75 struct all_same_as 76 { 77 static constexpr bool value = internal::TemplateConstraints::all_true< 78 std::is_same<Type, Types>::value...>::value; 79 }; 80 81 82 83 /* 84 * A generalization of `std::enable_if` that only works if 85 * <i>all</i> of the given boolean template parameters are 86 * true. 87 */ 88 template <bool... Values> 89 struct enable_if_all 90 : std::enable_if<internal::TemplateConstraints::all_true<Values...>::value> 91 {}; 92 93 94 95 /** 96 * A type trait that checks to see if a class behaves as an iterable container 97 * that has a beginning and an end. This implies that the class either defines 98 * the `begin()` and `end()` functions, or is a C-style array. 99 */ 100 template <typename T> 101 class has_begin_and_end 102 { 103 template <typename C> 104 static std::false_type 105 test(...); 106 107 template <typename C> 108 static auto 109 test(int) -> decltype(std::begin(std::declval<C>()), 110 std::end(std::declval<C>()), 111 std::true_type()); 112 113 public: 114 using type = decltype(test<T>(0)); 115 116 static const bool value = type::value; 117 }; 118 119 120 121 /** 122 * A template class that simply exports its template argument as a local 123 * alias. This class, while at first appearing useless, makes sense in the 124 * following context: if you have a function template as follows: 125 * @code 126 * template <typename T> 127 * void f(T, T); 128 * @endcode 129 * then it can't be called in an expression like <code>f(1, 3.141)</code> 130 * because the type <code>T</code> of the template can not be deduced in a 131 * unique way from the types of the arguments. However, if the template is 132 * written as 133 * @code 134 * template <typename T> 135 * void f(T, typename identity<T>::type); 136 * @endcode 137 * then the call becomes valid: the type <code>T</code> is not deducible from 138 * the second argument to the function, so only the first argument 139 * participates in template type resolution. 140 * 141 * The context for this feature is as follows: consider 142 * @code 143 * template <typename RT, typename A> 144 * void forward_call(RT (*p) (A), A a) 145 * { 146 * p(a); 147 * } 148 * 149 * void h (double); 150 * 151 * void g() 152 * { 153 * forward_call(&h, 1); 154 * } 155 * @endcode 156 * This code fails to compile because the compiler can't decide whether the 157 * template type <code>A</code> should be <code>double</code> (from the 158 * signature of the function given as first argument to 159 * <code>forward_call</code>, or <code>int</code> because the expression 160 * <code>1</code> has that type. Of course, what we would like the compiler to 161 * do is simply cast the <code>1</code> to <code>double</code>. We can achieve 162 * this by writing the code as follows: 163 * @code 164 * template <typename RT, typename A> 165 * void forward_call(RT (*p) (A), typename identity<A>::type a) 166 * { 167 * p(a); 168 * } 169 * 170 * void h (double); 171 * 172 * void g() 173 * { 174 * forward_call(&h, 1); 175 * } 176 * @endcode 177 */ 178 template <typename T> 179 struct identity 180 { 181 using type = T; 182 }; 183 184 185 186 /** 187 * A class to perform comparisons of arbitrary pointers for equality. In some 188 * circumstances, one would like to make sure that two arguments to a function 189 * are not the same object. One would, in this case, make sure that their 190 * addresses are not the same. However, sometimes the types of these two 191 * arguments may be template types, and they may be the same type or not. In 192 * this case, a simple comparison as in <tt>&object1 != &object2</tt> does 193 * only work if the types of the two objects are equal, but the compiler will 194 * barf if they are not. However, in the latter case, since the types of the 195 * two objects are different, we can be sure that the two objects cannot be 196 * the same. 197 * 198 * This class implements a comparison function that always returns @p false if 199 * the types of its two arguments are different, and returns <tt>p1 == p2</tt> 200 * otherwise. 201 */ 202 struct PointerComparison 203 { 204 /** 205 * Comparison function for pointers of the same type. Returns @p true if the 206 * two pointers are equal. 207 */ 208 template <typename T> 209 static bool equalPointerComparison210 equal(const T *p1, const T *p2) 211 { 212 return (p1 == p2); 213 } 214 215 216 /** 217 * Comparison function for pointers of different types. The C++ language 218 * does not allow comparing these pointers using <tt>operator==</tt>. 219 * However, since the two pointers have different types, we know that they 220 * can't be the same, so we always return @p false. 221 */ 222 template <typename T, typename U> 223 static bool equalPointerComparison224 equal(const T *, const U *) 225 { 226 return false; 227 } 228 }; 229 230 231 232 namespace internal 233 { 234 /** 235 * A struct that implements the default product type resulting from the 236 * multiplication of two types. 237 * 238 * @note Care should be taken when @p T or @p U have qualifiers (@p const or 239 * @p volatile) or are @p lvalue or @p rvalue references! It is recommended 240 * that specialization of this class is only made for unqualified (fully 241 * stripped) types and that the ProductType class be used to determine the 242 * result of operating with (potentially) qualified types. 243 */ 244 template <typename T, typename U> 245 struct ProductTypeImpl 246 { 247 using type = decltype(std::declval<T>() * std::declval<U>()); 248 }; 249 250 } // namespace internal 251 252 253 254 /** 255 * A class with a local alias that represents the type that results from the 256 * product of two variables of type @p T and @p U. In other words, we would 257 * like to infer the type of the <code>product</code> variable in code like 258 * this: 259 * @code 260 * T t; 261 * U u; 262 * auto product = t*u; 263 * @endcode 264 * The local alias of this structure represents the type the variable 265 * <code>product</code> would have. 266 * 267 * 268 * <h3>Where is this useful</h3> 269 * 270 * The purpose of this class is principally to represent the type one needs to 271 * use to represent the values or gradients of finite element fields at 272 * quadrature points. For example, assume you are storing the values $U_j$ of 273 * unknowns in a Vector<float>, then evaluating $u_h(x_q) = \sum_j U_j 274 * \varphi_j(x_q)$ at quadrature points results in values $u_h(x_q)$ that need 275 * to be stored as @p double variables because the $U_j$ are @p float values 276 * and the $\varphi_j(x_q)$ are computed as @p double values, and the product 277 * are then @p double values. On the other hand, if you store your unknowns 278 * $U_j$ as <code>std::complex@<double@></code> values and you try to evaluate 279 * $\nabla u_h(x_q) = \sum_j U_j \nabla\varphi_j(x_q)$ at quadrature points, 280 * then the gradients $\nabla u_h(x_q)$ need to be stored as objects of type 281 * <code>Tensor@<1,dim,std::complex@<double@>@></code> because that's what you 282 * get when you multiply a complex number by a <code>Tensor@<1,dim@></code> 283 * (the type used to represent the gradient of shape functions of scalar 284 * finite elements). 285 * 286 * Likewise, if you are using a vector valued element (with dim components) 287 * and the $U_j$ are stored as @p double variables, then $u_h(x_q) = \sum_j 288 * U_j \varphi_j(x_q)$ needs to have type <code>Tensor@<1,dim@></code> 289 * (because the shape functions have type <code>Tensor@<1,dim@></code>). 290 * Finally, if you store the $U_j$ as objects of type 291 * <code>std::complex@<double@></code> and you have a vector valued element, 292 * then the gradients $\nabla u_h(x_q) = \sum_j U_j \nabla\varphi_j(x_q)$ will 293 * result in objects of type <code>Tensor@<2,dim,std::complex@<double@> 294 * @></code>. 295 * 296 * In all of these cases, this type is used to identify which type needs to be 297 * used for the result of computing the product of unknowns and the values, 298 * gradients, or other properties of shape functions. 299 */ 300 template <typename T, typename U> 301 struct ProductType 302 { 303 using type = 304 typename internal::ProductTypeImpl<typename std::decay<T>::type, 305 typename std::decay<U>::type>::type; 306 }; 307 308 namespace internal 309 { 310 // Annoyingly, there is no std::complex<T>::operator*(U) for scalars U 311 // other than T (not even in C++11, or C++14). We provide our own overloads 312 // in base/complex_overloads.h, but in order for them to work, we have to 313 // manually specify all products we want to allow: 314 315 template <typename T> 316 struct ProductTypeImpl<std::complex<T>, std::complex<T>> 317 { 318 using type = std::complex<T>; 319 }; 320 321 template <typename T, typename U> 322 struct ProductTypeImpl<std::complex<T>, std::complex<U>> 323 { 324 using type = std::complex<typename ProductType<T, U>::type>; 325 }; 326 327 template <typename U> 328 struct ProductTypeImpl<double, std::complex<U>> 329 { 330 using type = std::complex<typename ProductType<double, U>::type>; 331 }; 332 333 template <typename T> 334 struct ProductTypeImpl<std::complex<T>, double> 335 { 336 using type = std::complex<typename ProductType<T, double>::type>; 337 }; 338 339 template <typename U> 340 struct ProductTypeImpl<float, std::complex<U>> 341 { 342 using type = std::complex<typename ProductType<float, U>::type>; 343 }; 344 345 template <typename T> 346 struct ProductTypeImpl<std::complex<T>, float> 347 { 348 using type = std::complex<typename ProductType<T, float>::type>; 349 }; 350 351 } // namespace internal 352 353 354 355 /** 356 * This class provides a local alias @p type that is equal to the template 357 * argument but only if the template argument corresponds to a scalar type 358 * (i.e., one of the floating point types, signed or unsigned integer, or a 359 * complex number). If the template type @p T is not a scalar, then no class 360 * <code>EnableIfScalar@<T@></code> is declared and, consequently, no local 361 * alias is available. 362 * 363 * The purpose of the class is to disable certain template functions if one of 364 * the arguments is not a scalar number. By way of (nonsensical) example, 365 * consider the following function: 366 * @code 367 * template <typename T> 368 * T multiply (const T t1, const T t2) 369 * { 370 * return t1*t2; 371 * } 372 * @endcode 373 * This function can be called with any two arguments of the same type @p T. 374 * This includes arguments for which this clearly makes no sense. 375 * Consequently, one may want to restrict the function to only scalars, and 376 * this can be written as 377 * @code 378 * template <typename T> 379 * typename EnableIfScalar<T>::type 380 * multiply (const T t1, const T t2) 381 * { 382 * return t1*t2; 383 * } 384 * @endcode 385 * At a place where you call the function, the compiler will deduce the type 386 * @p T from the arguments. For example, in 387 * @code 388 * multiply(1.234, 2.345); 389 * @endcode 390 * it will deduce @p T to be @p double, and because 391 * <code>EnableIfScalar@<double@>::%type</code> equals @p double, the compiler 392 * will instantiate a function <code>double multiply(const double, const 393 * double)</code> from the template above. On the other hand, in a context 394 * like 395 * @code 396 * std::vector<char> v1, v2; 397 * multiply(v1, v2); 398 * @endcode 399 * the compiler will deduce @p T to be <code>std::vector@<char@></code> but 400 * because <code>EnableIfScalar@<std::vector@<char@>@>::%type</code> does not 401 * exist the compiler does not consider the template for instantiation. This 402 * technique is called "Substitution Failure is not an Error (SFINAE)". It 403 * makes sure that the template function can not even be called, rather than 404 * leading to a later error about the fact that the operation 405 * <code>t1*t2</code> is not defined (or may lead to some nonsensical result). 406 * It also allows the declaration of overloads of a function such as @p 407 * multiply for different types of arguments, without resulting in ambiguous 408 * call errors by the compiler. 409 */ 410 template <typename T> 411 struct EnableIfScalar; 412 413 414 template <> 415 struct EnableIfScalar<double> 416 { 417 using type = double; 418 }; 419 420 template <> 421 struct EnableIfScalar<float> 422 { 423 using type = float; 424 }; 425 426 template <> 427 struct EnableIfScalar<long double> 428 { 429 using type = long double; 430 }; 431 432 template <> 433 struct EnableIfScalar<int> 434 { 435 using type = int; 436 }; 437 438 template <> 439 struct EnableIfScalar<unsigned int> 440 { 441 using type = unsigned int; 442 }; 443 444 template <typename T> 445 struct EnableIfScalar<std::complex<T>> 446 { 447 using type = std::complex<T>; 448 }; 449 450 451 DEAL_II_NAMESPACE_CLOSE 452 453 #endif 454