Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TypeTraits.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TypeTraits.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #pragma once
10 
11 #include <functional>
12 #include <string>
13 #include <type_traits>
14 
15 namespace Acts {
16 
17 namespace detail {
18 
44 
46 struct nonesuch {
47  ~nonesuch() = delete;
48  nonesuch(nonesuch const&) = delete;
49  void operator=(nonesuch const&) = delete;
50 };
51 
58 template <class Default, class AlwaysVoid, template <class...> class Op,
59  class... Args>
60 struct detector {
62  using type = Default;
63 };
64 
69 template <class Default, template <class...> class Op, class... Args>
70 struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
71  // Note that std::void_t is a C++17 feature
73  using type = Op<Args...>;
74 };
75 
76 } // namespace detail
77 
78 namespace Concepts {
79 
86 template <template <class...> class Op, class... Args>
87 using is_detected =
89 
94 template <template <class...> class Op, class... Args>
95 using detected_t =
96  typename detail::detector<detail::nonesuch, void, Op, Args...>::type;
97 
103 template <class Expected, template <class...> class Op, class... Args>
104 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
105 
112 template <class To, template <class...> class Op, class... Args>
114  std::is_convertible<detected_t<Op, Args...>, To>;
115 
121 template <class Default, template <class...> class Op, class... Args>
122 using detected_or = detail::detector<Default, void, Op, Args...>;
123 
127 
131 template <bool... Bs>
132 constexpr bool require = std::conjunction<std::bool_constant<Bs>...>::value;
133 
137 template <bool... Bs>
138 constexpr bool either = std::disjunction<std::bool_constant<Bs>...>::value;
139 
142 template <bool... Bs>
143 constexpr bool disallow = not require<Bs...>;
144 
148 template <template <class...> class Op, class... Args>
149 constexpr bool exists = is_detected<Op, Args...>::value;
150 
155 template <class To, template <class...> class Op, class... Args>
156 constexpr bool converts_to = is_detected_convertible<To, Op, Args...>::value;
157 
162 template <class Exact, template <class...> class Op, class... Args>
163 constexpr bool identical_to = is_detected_exact<Exact, Op, Args...>::value;
164 
172 template <typename T, typename R, template <class...> class M,
173  typename... Arguments>
174 constexpr bool has_method = M<T, R, Arguments...>::template tv<T>::value;
175 
181 template <typename T, template <class...> class M, typename V>
182 constexpr bool has_member = identical_to<V, M, T>;
183 
185 } // namespace Concepts
186 } // namespace Acts
187 
320 
322 
327 #define METHOD_TRAIT(trait_name, method_name) \
328  template <class T, typename R, typename... Arguments> \
329  struct trait_name { \
330  /* Meta function to check if a type has a const qualifier*/ \
331  /* (by stripping it and seeing if something changed */ \
332  template <typename T_> \
333  static constexpr bool is_const = \
334  not std::is_same_v<std::remove_const_t<T_>, T_>; \
335  \
336  /*These following meta-functions basically to this: they check whether or \
337  * not the actual function pointer extracted through ``&T::method_name`` \
338  * can \
339  * be assigned to a prepared function pointer type with the given \
340  * signature. This checks the exact signature, and not just callability \
341  * and validity of the expression. */ \
342  \
343  /* Meta function which constructs the right type to check a function \
344  * pointer, non-const version*/ \
345  template <typename T_, typename = int> \
346  struct fptr_meta { \
347  template <typename... Arguments_> \
348  using type = typename std::integral_constant< \
349  decltype(std::declval<T_>().method_name( \
350  std::declval<Arguments_>()...)) (T_::*)(Arguments_...), \
351  &T_::method_name>::value_type; \
352  }; \
353  \
354  /* Meta function which constructs the right type to check a function \
355  * pointer, const version*/ \
356  /* The ``const`` needs to be put in there in one specific spot, that's why \
357  * the metafunction is needed*/ \
358  template <typename T_> \
359  struct fptr_meta<T_, std::enable_if_t<is_const<T_>, int>> { \
360  template <typename... Arguments_> \
361  using type = typename std::integral_constant< \
362  decltype(std::declval<T_>().method_name( \
363  std::declval<Arguments_>()...)) (T_::*)(Arguments_...) const, \
364  &T_::method_name>::value_type; \
365  }; \
366  \
367  /* Helper on top of the function pointer metafunction */ \
368  template <typename T_, typename... Arguments_> \
369  using fptr_meta_t = typename fptr_meta<T_>::template type<Arguments_...>; \
370  \
371  /* Trait check for the qualifier and the return type of the function */ \
372  /* This does not check the const qualifier at all */ \
373  template <typename T_, typename... Arguments_> \
374  using qual_ret = decltype(std::declval<T_>().method_name( \
375  std::declval<Arguments_>()...)); \
376  \
377  /* The problem is this: while the above is fine with and without const, \
378  * and with and without exact argument type match, the assignment to the \
379  * function pointer fails hard if there is no method at all with the given \
380  * name. That is undesirable. The following first uses the expression \
381  * validity check to assert that there is in fact a method of the given \
382  * name, and only if that is the case, try to compile the function pointer \
383  * based signature check. That way, there is no hard failures, only \
384  * substitution failures and we're happy. */ \
385  template <typename T_, typename = int> \
386  struct tv { \
387  static constexpr bool value = false; \
388  }; \
389  template <typename T_> \
390  struct tv<T_, std::enable_if_t<Acts::Concepts::is_detected_exact< \
391  R, qual_ret, T_, Arguments...>::value, \
392  int>> { \
393  /* This is only ever evaluate if the method exists!*/ \
394  static constexpr bool value = \
395  Acts::Concepts::is_detected<fptr_meta_t, T, Arguments...>::value; \
396  }; \
397  }
398