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