Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TypeTraits.hxx
Go to the documentation of this file.
1 // @(#)root/foundation:
2 // Author: Axel Naumann, Enrico Guiraud, June 2017
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #ifndef ROOT_TypeTraits
13 #define ROOT_TypeTraits
14 
15 #include <memory> // shared_ptr, unique_ptr for IsSmartOrDumbPtr
16 #include <type_traits>
17 #include <vector> // for IsContainer
18 #include "ROOT/RSpan.hxx" // for IsContainer
19 
20 namespace ROOT {
21 
22 /// ROOT type_traits extensions
23 namespace TypeTraits {
24 /// Lightweight storage for a collection of types.
25 /// Differently from std::tuple, no instantiation of objects of stored types is performed
26 template <typename... Types>
27 struct TypeList {
28  static constexpr std::size_t list_size = sizeof...(Types);
29 };
30 } // end ns TypeTraits
31 
32 namespace Detail {
33 template <typename T> constexpr auto HasCallOp(int /*goodOverload*/) -> decltype(&T::operator(), true) { return true; }
34 template <typename T> constexpr bool HasCallOp(char /*badOverload*/) { return false; }
35 
36 /// Extract types from the signature of a callable object. See CallableTraits.
37 template <typename T, bool HasCallOp = ROOT::Detail::HasCallOp<T>(0)>
38 struct CallableTraitsImpl {};
39 
40 // Extract signature of operator() and delegate to the appropriate CallableTraitsImpl overloads
41 template <typename T>
42 struct CallableTraitsImpl<T, true> {
43  using arg_types = typename CallableTraitsImpl<decltype(&T::operator())>::arg_types;
44  using arg_types_nodecay = typename CallableTraitsImpl<decltype(&T::operator())>::arg_types_nodecay;
45  using ret_type = typename CallableTraitsImpl<decltype(&T::operator())>::ret_type;
46 };
47 
48 // lambdas, std::function, const member functions
49 template <typename R, typename T, typename... Args>
50 struct CallableTraitsImpl<R (T::*)(Args...) const, false> {
51  using arg_types = ROOT::TypeTraits::TypeList<typename std::decay<Args>::type...>;
52  using arg_types_nodecay = ROOT::TypeTraits::TypeList<Args...>;
53  using ret_type = R;
54 };
55 
56 // mutable lambdas and functor classes, non-const member functions
57 template <typename R, typename T, typename... Args>
58 struct CallableTraitsImpl<R (T::*)(Args...), false> {
59  using arg_types = ROOT::TypeTraits::TypeList<typename std::decay<Args>::type...>;
60  using arg_types_nodecay = ROOT::TypeTraits::TypeList<Args...>;
61  using ret_type = R;
62 };
63 
64 // function pointers
65 template <typename R, typename... Args>
66 struct CallableTraitsImpl<R (*)(Args...), false> {
67  using arg_types = ROOT::TypeTraits::TypeList<typename std::decay<Args>::type...>;
68  using arg_types_nodecay = ROOT::TypeTraits::TypeList<Args...>;
69  using ret_type = R;
70 };
71 
72 // free functions
73 template <typename R, typename... Args>
74 struct CallableTraitsImpl<R(Args...), false> {
75  using arg_types = ROOT::TypeTraits::TypeList<typename std::decay<Args>::type...>;
76  using arg_types_nodecay = ROOT::TypeTraits::TypeList<Args...>;
77  using ret_type = R;
78 };
79 } // end ns Detail
80 
81 namespace TypeTraits {
82 
83 ///\class ROOT::TypeTraits::
84 template <class T>
85 class IsSmartOrDumbPtr : public std::integral_constant<bool, std::is_pointer<T>::value> {
86 };
87 
88 template <class P>
89 class IsSmartOrDumbPtr<std::shared_ptr<P>> : public std::true_type {
90 };
91 
92 template <class P>
93 class IsSmartOrDumbPtr<std::unique_ptr<P>> : public std::true_type {
94 };
95 
96 /// Check for container traits.
97 template <typename T>
98 struct IsContainer {
99  using Test_t = typename std::decay<T>::type;
100 
101  template <typename A>
102  static constexpr bool Test(A *pt, A const *cpt = nullptr, decltype(pt->begin()) * = nullptr,
103  decltype(pt->end()) * = nullptr, decltype(cpt->begin()) * = nullptr,
104  decltype(cpt->end()) * = nullptr, typename A::iterator *pi = nullptr,
105  typename A::const_iterator *pci = nullptr)
106  {
107  using It_t = typename A::iterator;
108  using CIt_t = typename A::const_iterator;
109  using V_t = typename A::value_type;
110  return std::is_same<Test_t, std::vector<bool>>::value ||
111  (std::is_same<decltype(pt->begin()), It_t>::value && std::is_same<decltype(pt->end()), It_t>::value &&
112  std::is_same<decltype(cpt->begin()), CIt_t>::value && std::is_same<decltype(cpt->end()), CIt_t>::value &&
113  std::is_same<decltype(**pi), V_t &>::value && std::is_same<decltype(**pci), V_t const &>::value);
114  }
115 
116  template <typename A>
117  static constexpr bool Test(...)
118  {
119  return false;
120  }
121 
122  static constexpr bool value = Test<Test_t>(nullptr);
123 };
124 
125 template<typename T>
126 struct IsContainer<std::span<T>> {
127  static constexpr bool value = true;
128 };
129 
130 /// Checks for signed integers types that are not characters
131 template<class T>
132 struct IsSignedNumeral : std::integral_constant<bool,
133  std::is_integral<T>::value &&
134  std::is_signed<T>::value &&
135  !std::is_same<T, char>::value
136 > {};
137 
138 /// Checks for unsigned integer types that are not characters
139 template<class T>
140 struct IsUnsignedNumeral : std::integral_constant<bool,
141  std::is_integral<T>::value &&
142  !std::is_signed<T>::value &&
143  !std::is_same<T, char>::value
144 > {};
145 
146 /// Checks for floating point types (that are not characters)
147 template<class T>
148 using IsFloatNumeral = std::is_floating_point<T>;
149 
150 /// Extract types from the signature of a callable object.
151 /// The `CallableTraits` struct contains three type aliases:
152 /// - arg_types: a `TypeList` of all types in the signature, decayed through std::decay
153 /// - arg_types_nodecay: a `TypeList` of all types in the signature, including cv-qualifiers
154 template<typename F>
155 using CallableTraits = ROOT::Detail::CallableTraitsImpl<F>;
156 
157 // Return first of a variadic list of types.
158 template <typename T, typename... Rest>
159 struct TakeFirstType {
160  using type = T;
161 };
162 
163 template <typename... Types>
164 using TakeFirstType_t = typename TakeFirstType<Types...>::type;
165 
166 // Remove first type from a variadic list of types, return a TypeList containing the rest.
167 // e.g. RemoveFirst_t<A,B,C> is TypeList<B,C>
168 template <typename T, typename... Rest>
169 struct RemoveFirst {
170  using type = TypeList<Rest...>;
171 };
172 
173 template <typename... Args>
174 using RemoveFirst_t = typename RemoveFirst<Args...>::type;
175 
176 /// Return first of possibly many template parameters.
177 /// For non-template types, the result is void
178 /// e.g. TakeFirstParameter<U<A,B>> is A
179 /// TakeFirstParameter<T> is void
180 template <typename T>
181 struct TakeFirstParameter {
182  using type = void;
183 };
184 
185 template <template <typename...> class Template, typename T, typename... Rest>
186 struct TakeFirstParameter<Template<T, Rest...>> {
187  using type = T;
188 };
189 
190 template <typename T>
191 using TakeFirstParameter_t = typename TakeFirstParameter<T>::type;
192 
193 /// Remove first of possibly many template parameters.
194 /// e.g. RemoveFirstParameter_t<U<A,B>> is U<B>
195 template <typename>
196 struct RemoveFirstParameter {
197 };
198 
199 template <typename T, template <typename...> class U, typename... Rest>
200 struct RemoveFirstParameter<U<T, Rest...>> {
201  using type = U<Rest...>;
202 };
203 
204 template <typename T>
205 using RemoveFirstParameter_t = typename RemoveFirstParameter<T>::type;
206 
207 template <typename T>
208 struct HasBeginAndEnd {
209 
210  template <typename V>
211  using Begin_t = typename V::const_iterator (V::*)() const;
212 
213  template <typename V>
214  using End_t = typename V::const_iterator (V::*)() const;
215 
216  template <typename V>
217  static constexpr auto Check(int)
218  -> decltype(static_cast<Begin_t<V>>(&V::begin), static_cast<End_t<V>>(&V::end), true)
219  {
220  return true;
221  }
222 
223  template <typename V>
224  static constexpr bool Check(...)
225  {
226  return false;
227  }
228 
229  static constexpr bool const value = Check<T>(0);
230 };
231 
232 } // ns TypeTraits
233 } // ns ROOT
234 #endif // ROOT_TTypeTraits