1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 // vi: set et ts=4 sw=2 sts=2: 3 #ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH 4 #define DUNE_COMMON_STD_TYPE_TRAITS_HH 5 6 #include <type_traits> 7 #include <dune/common/typetraits.hh> 8 #include <dune/common/typeutilities.hh> 9 10 #if __has_include(<experimental/type_traits>) 11 #include <experimental/type_traits> 12 #endif 13 14 namespace Dune 15 { 16 17 //! Namespace for features backported from new C++ standards 18 /** 19 * The namespace Dune::Std contains library features of new C++ standards and 20 * technical specifications backported to older compilers. Most features are 21 * detected and pulled into this namespace from the standard library if your 22 * compiler has native support. If it doesn't, we provide a fallback implementation 23 * on a best-effort basis. 24 * 25 * \ingroup CxxUtilities 26 */ 27 namespace Std 28 { 29 30 // to_false_type 31 // ------------- 32 33 /** \class to_false_type 34 * 35 * \brief template mapping a type to <tt>std::false_type</tt> 36 * \deprecated Use Dune::AlwaysFalse (from dune/common/typetraits.hh) instead 37 * \tparam T Some type 38 * 39 * Suppose you have a template class. You want to document the required 40 * members of this class in the non-specialized template, but you know that 41 * actually instantiating the non-specialized template is an error. You can 42 * try something like this: 43 * \code 44 * template<typename T> 45 * struct Traits 46 * { 47 * static_assert(false, 48 * "Instanciating this non-specialized template is an " 49 * "error. You should use one of the specializations " 50 * "instead."); 51 * //! The type used to frobnicate T 52 * typedef void FrobnicateType; 53 * }; 54 * \endcode 55 * This will trigger static_assert() as soon as the compiler reads the 56 * definition for the Traits template, since it knows that "false" can never 57 * become true, no matter what the template parameters of Traits are. As a 58 * workaround you can use to_false_type: replace <tt>false</tt> by 59 * <tt>to_false_type<T>::value</tt>, like this: 60 * \code 61 * template<typename T> 62 * struct Traits 63 * { 64 * static_assert(Std::to_false_type<T>::value, 65 * "Instanciating this non-specialized template is an " 66 * "error. You should use one of the specializations " 67 * "instead."); 68 * //! The type used to frobnicate T 69 * typedef void FrobnicateType; 70 * }; 71 * \endcode 72 * Since there might be an specialization of to_false_type for template 73 * parameter T, the compiler cannot trigger static_assert() until the type 74 * of T is known, that is, until Traits<T> is instantiated. 75 * 76 * \ingroup CxxUtilities 77 */ 78 template< typename T > 79 struct [[deprecated("Will be removed after release 2.8. Use Dune::AlwaysFalse (from dune/common/typetraits.hh)")]] to_false_type : public std::false_type {}; 80 81 82 83 // to_true_type 84 // ------------ 85 86 /** \class to_true_type 87 * 88 * \brief template mapping a type to <tt>std::true_type</tt> 89 * \deprecated Use Dune::AlwaysFalse (from dune/common/typetraits.hh) instead 90 * \tparam T Some type 91 * 92 * \note This class exists mostly for consistency with to_false_type. 93 * 94 * \ingroup CxxUtilities 95 */ 96 template< typename T > 97 struct [[deprecated("Will be removed after release 2.8. Use Dune::AlwaysTrue (from dune/common/typetraits.hh)")]] to_true_type : public std::true_type {}; 98 99 100 /// A helper alias template std::bool_constant imported into the namespace Dune::Std 101 /// \deprecated Use the `std::bool_constant` directly. 102 using std::bool_constant; 103 104 105 namespace Impl { 106 107 // If R is void we only need to check if F can be called 108 // with given Args... list. If this is not possible 109 // result_of_t is not defined and this overload is disabled. 110 template<class R, class F, class... Args, 111 std::enable_if_t< 112 std::is_same<std::void_t<std::result_of_t<F(Args...)>>, R>::value 113 , int> = 0> is_callable_helper(PriorityTag<2>)114 std::true_type is_callable_helper(PriorityTag<2>) 115 { return {}; } 116 117 // Check if result of F(Args...) can be converted to R. 118 // If F cannot even be called with given Args... then 119 // result_of_t is not defined and this overload is disabled. 120 template<class R, class F, class... Args, 121 std::enable_if_t< 122 std::is_convertible<std::result_of_t<F(Args...)>, R>::value 123 , int> = 0> is_callable_helper(PriorityTag<1>)124 std::true_type is_callable_helper(PriorityTag<1>) 125 { return {}; } 126 127 // If none of the above matches, F can either not be called 128 // with given Args..., or the result cannot be converted to 129 // void, or R is not void. 130 template<class R, class F, class... Args> is_callable_helper(PriorityTag<0>)131 std::false_type is_callable_helper(PriorityTag<0>) 132 { return {}; } 133 } 134 135 /** 136 * \brief Traits class to check if function is callable 137 * \deprecated Use std::is_invocable from <type_traits> 138 * 139 * \tparam D Function descriptor 140 * \tparam R Return value 141 * 142 * If D = F(Args...) this checks if F can be called with an 143 * argument list of type Args..., and if the return value can 144 * be converted to R. If R is void, any return type is accepted. 145 * The result is encoded by deriving from std::integral_constant<bool, result>. 146 * 147 * If D is not of the form D = F(Args...) this class is not defined. 148 * 149 * This implements std::is_callable as proposed in N4446 for C++17. 150 * 151 * \ingroup CxxUtilities 152 */ 153 template <class D, class R= void> 154 struct is_callable; 155 156 /** 157 * \brief Traits class to check if function is callable 158 * \deprecated Use std::is_invocable from <type_traits> 159 * 160 * \tparam D Function descriptor 161 * \tparam R Return value 162 * 163 * If D = F(Args...) this checks if F can be called with an 164 * argument list of type Args..., and if the return value can 165 * be converted to R. If R is void, any return type is accepted. 166 * The result is encoded by deriving from std::integral_constant<bool, result>. 167 * 168 * If D is not of the form D = F(Args...) this class is not defined. 169 * 170 * This implements std::is_callable as proposed in N4446 for C++17. 171 * 172 * \ingroup CxxUtilities 173 */ 174 template <class F, class... Args, class R> 175 struct [[deprecated("Use std::is_invocable from <type_traits>. Will be removed after release 2.8")]] is_callable< F(Args...), R> : 176 decltype(Impl::is_callable_helper<R, F, Args...>(PriorityTag<42>())) 177 {}; 178 179 180 /** 181 * \brief Traits class to check if function is invocable 182 * \deprecated Use std::is_invocable from <type_traits> 183 * 184 * \tparam F Function to check 185 * \tparam Args Function arguments to check 186 * 187 * This checks if F can be called with an arguments list of type Args.... 188 * The result is encoded by deriving from std::integral_constant<bool, result>. 189 * 190 * This implements std::is_invocable from C++17. 191 * 192 * \ingroup CxxUtilities 193 */ 194 template <class F, class... Args> 195 struct [[deprecated("Use std::is_invocable from <type_traits>. Will be removed after release 2.8")]] is_invocable : 196 decltype(Impl::is_callable_helper<void, F, Args...>(PriorityTag<42>())) 197 {}; 198 199 /** 200 * \brief Traits class to check if function is invocable and the return type is compatible 201 * \deprecated Use std::is_invocable_r from <type_traits> 202 * 203 * \tparam R Desired result type 204 * \tparam F Function to check 205 * \tparam Args Function arguments to check 206 * 207 * This checks if F can be called with an arguments list of type Args..., and 208 * if the return value can be converted to R. 209 * The result is encoded by deriving from std::integral_constant<bool, result>. 210 * 211 * This implements std::is_invocable_r from C++17. 212 * 213 * \ingroup CxxUtilities 214 */ 215 template <class R, class F, class... Args> 216 struct [[deprecated("Use std::is_invocable_r from <type_traits>. Will be removed after release 2.8")]] is_invocable_r : 217 decltype(Impl::is_callable_helper<R, F, Args...>(PriorityTag<42>())) 218 {}; 219 220 221 #if DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED 222 223 using std::experimental::nonesuch; 224 using std::experimental::detected_or; 225 using std::experimental::is_detected; 226 using std::experimental::detected_t; 227 using std::experimental::is_detected_v; 228 using std::experimental::detected_or_t; 229 using std::experimental::is_detected_exact; 230 using std::experimental::is_detected_exact_v; 231 using std::experimental::is_detected_convertible; 232 using std::experimental::is_detected_convertible_v; 233 234 #else // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED 235 236 // fallback version of std::experimental::is_detected et al., heavily scribbled 237 // from cppreference.com (but there is actually not much implementation to the thing) 238 239 #ifndef DOXYGEN 240 241 namespace Impl { 242 243 // default version of detector, this gets matched on failure 244 template<typename Default, typename Void, template<typename...> class Op, typename... Args> 245 struct detector 246 { 247 using value_t = std::false_type; 248 using type = Default; 249 }; 250 251 // specialization of detector that matches if Op<Args...> can be instantiated 252 template<typename Default, template<typename...> class Op, typename... Args> 253 struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> 254 { 255 using value_t = std::true_type; 256 using type = Op<Args...>; 257 }; 258 259 } 260 261 #endif // DOXYGEN 262 263 //! Type representing a lookup failure by std::detected_or and friends. 264 /** 265 * This type cannot be constructed, destroyed or copied. 266 * 267 * \note This functionality is part of the C++ library fundamentals TS v2 and might 268 * or might not became part of C++2a. 269 * 270 * \ingroup CxxUtilities 271 */ 272 struct nonesuch 273 { 274 nonesuch() = delete; 275 ~nonesuch() = delete; 276 nonesuch(const nonesuch&) = delete; 277 void operator=(const nonesuch&) = delete; 278 }; 279 280 //! Detects whether `Op<Args...>` is valid and makes the result available. 281 /** 282 * This alias template is an alias for an unspecified class type with two 283 * nested `typedefs` `value_t` and `type`. It can be used to detect whether 284 * the meta function call `Op<Args...>` is valid and access the result of 285 * the call by inspecting the returned type, which is defined as follows: 286 * 287 * * If `Op<Args...>` can be instantiated, `value_t` is an alias for `std::true_type` 288 * and `type` is an alias for `Op<Args...>`. 289 * * If `Op<Args...>` is invalid, `value_t` is an alias for `std::false_type` 290 * and `type` is an alias for `Default`. 291 * 292 * This can be used to safely extract a nested `typedef` from a type `T` that 293 * might not define the `typedef`: 294 \code 295 struct A { using size_type = int ; }; 296 struct B; 297 298 template<typename T> 299 using SizeType = typename T::size_type; 300 301 // this extracts the nested typedef for int 302 using st_a = typename detected_or<std::size_t,SizeType,A>::type; 303 // as there is no nested typedef in B, this yields std::size_t 304 using st_b = typename detected_or<std::size_t,SizeType,B>::type; 305 \endcode 306 * 307 * \note This functionality is part of the C++ library fundamentals TS v2 and might 308 * or might not became part of C++2a. 309 * 310 * \ingroup CxxUtilities 311 */ 312 template<typename Default, template<typename...> class Op, typename... Args> 313 using detected_or = Impl::detector<Default,void,Op,Args...>; 314 315 //! Detects whether `Op<Args...>` is valid. 316 /** 317 * This alias template checks whether `Op<Args...>` can be instantiated. It is 318 * equivalent to `typename detected_or<nonesuch,Op,Args...>::value_t`. 319 * 320 * \note This functionality is part of the C++ library fundamentals TS v2 and might 321 * or might not became part of C++2a. 322 * 323 * \ingroup CxxUtilities 324 */ 325 template<template<typename...> class Op, typename... Args> 326 using is_detected = typename detected_or<nonesuch,Op,Args...>::value_t; 327 328 #ifdef __cpp_variable_templates 329 //! Detects whether `Op<Args...>` is valid and makes the result available as a value. 330 /** 331 * This constexpr variable checks whether `Op<Args...>` can be instantiated. It is 332 * equivalent to `is_detected<Op,Args...>::value`. 333 * 334 * \note This functionality is part of the C++ library fundamentals TS v2 and might 335 * or might not became part of C++2a. 336 * 337 * \ingroup CxxUtilities 338 */ 339 template<template<typename...> class Op, typename... Args> 340 constexpr bool is_detected_v = is_detected<Op,Args...>::value; 341 #endif // __cpp_variable_templates 342 343 //! Returns `Op<Args...>` if that is valid; otherwise returns nonesuch. 344 /** 345 * This alias template can be used to instantiate `Op<Args...>` in a context that is 346 * not SFINAE-safe by appropriately wrapping the instantiation. If instantiation fails, 347 * the marker type nonesuch is returned instead. 348 * 349 * \note This functionality is part of the C++ library fundamentals TS v2 and might 350 * or might not became part of C++2a. 351 * 352 * \ingroup CxxUtilities 353 */ 354 template<template<typename...> class Op, typename... Args> 355 using detected_t = typename detected_or<nonesuch,Op,Args...>::type; 356 357 358 //! Returns `Op<Args...>` if that is valid; otherwise returns the fallback type `Default`. 359 /** 360 * This alias template can be used to instantiate `Op<Args...>` in a context that is 361 * not SFINAE-safe by appropriately wrapping the instantiation and automatically falling back 362 * to `Default` if instantiation fails. 363 * 364 * \note This functionality is part of the C++ library fundamentals TS v2 and might 365 * or might not became part of C++2a. 366 * 367 * \ingroup CxxUtilities 368 */ 369 template<typename Default, template<typename...> class Op, typename... Args> 370 using detected_or_t = typename detected_or<Default,Op,Args...>::type; 371 372 //! Checks whether `Op<Args...>` is `Expected` without causing an error if `Op<Args...>` is invalid. 373 /** 374 * \note This functionality is part of the C++ library fundamentals TS v2 and might 375 * or might not became part of C++2a. 376 * 377 * \ingroup CxxUtilities 378 */ 379 template<typename Expected, template<typename...> class Op, typename... Args> 380 using is_detected_exact = std::is_same<Expected,detected_t<Op,Args...>>; 381 382 #ifdef __cpp_variable_templates 383 //! Convenient access to the result value of is_detected_exact. 384 /** 385 * \note This functionality is part of the C++ library fundamentals TS v2 and might 386 * or might not became part of C++2a. 387 * 388 * \ingroup CxxUtilities 389 */ 390 template<typename Expected, template<typename...> class Op, typename... Args> 391 constexpr bool is_detected_exact_v = is_detected_exact<Expected,Op,Args...>::value; 392 #endif // __cpp_variable_templates 393 394 //! Checks whether `Op<Args...>` is convertible to `Target` without causing an error if `Op<Args...>` is invalid. 395 /** 396 * \note This functionality is part of the C++ library fundamentals TS v2 and might 397 * or might not became part of C++2a. 398 * 399 * \ingroup CxxUtilities 400 */ 401 template<typename Target, template<typename...> class Op, typename... Args> 402 using is_detected_convertible = std::is_convertible<Target,detected_t<Op,Args...>>; 403 404 #ifdef __cpp_variable_templates 405 //! Convenient access to the result value of is_detected_convertible. 406 /** 407 * \note This functionality is part of the C++ library fundamentals TS v2 and might 408 * or might not became part of C++2a. 409 * 410 * \ingroup CxxUtilities 411 */ 412 template<typename Target, template<typename...> class Op, typename... Args> 413 constexpr bool is_detected_convertible_v = is_detected_convertible<Target,Op,Args...>::value; 414 #endif // __cpp_variable_templates 415 416 #endif // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED 417 418 419 420 // conjunction 421 // ----------- 422 423 /** 424 * \brief forms the logical conjunction of the type traits B... 425 * 426 * \note This functionality is part of the C++17 standard. 427 * 428 * \ingroup CxxUtilities 429 **/ 430 template< class... B > 431 struct [[deprecated("Will be removed after release 2.8. Use std::conjuction instead.")]] conjunction 432 : std::conjunction<B...> 433 {}; 434 435 436 // disjunction 437 // ----------- 438 439 /** 440 * \brief forms the logical disjunction of the type traits B... 441 * 442 * \note This functionality is part of the C++17 standard. 443 * 444 * \ingroup CxxUtilities 445 **/ 446 template< class... B > 447 struct [[deprecated("Will be removed after release 2.8. Use std::disjunction instead.")]] disjunction 448 : std::disjunction<B...> 449 {}; 450 451 452 // negation 453 // -------- 454 455 /** 456 * \brief forms the logical negation of the type traits B... 457 * 458 * \note This functionality is part of the C++17 standard. 459 * 460 * \ingroup CxxUtilities 461 **/ 462 template<class B> 463 struct [[deprecated("Will be removed after release 2.8. Use std::negation instead.")]] negation 464 : std::negation<B> 465 {}; 466 467 } // namespace Std 468 469 } // namespace Dune 470 471 #endif // #ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH 472