HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TypeList.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file TypeList.h
5 ///
6 /// @brief A TypeList provides a compile time sequence of heterogeneous types
7 /// which can be accessed, transformed and executed over in various ways.
8 /// It incorporates a subset of functionality similar to hboost::mpl::vector
9 /// however provides most of its content through using declarations rather
10 /// than additional typed classes.
11 
12 #ifndef OPENVDB_TYPELIST_HAS_BEEN_INCLUDED
13 #define OPENVDB_TYPELIST_HAS_BEEN_INCLUDED
14 
15 #include "version.h"
16 
17 #include <tuple>
18 #include <type_traits>
19 
20 namespace openvdb {
22 namespace OPENVDB_VERSION_NAME {
23 
24 /// @cond OPENVDB_TYPES_INTERNAL
25 
26 template<typename... Ts> struct TypeList; // forward declaration
27 
28 namespace typelist_internal {
29 
30 // Implementation details of @c TypeList
31 
32 /// @brief Dummy struct, used as the return type from invalid or out-of-range
33 /// @c TypeList queries.
34 struct NullType {};
35 
36 
37 /// @brief Type resolver for index queries
38 /// @details Defines a type at a given location within a @c TypeList or the
39 /// @c NullType if the index is out-of-range. The last template
40 /// parameter is used to determine if the index is in range.
41 /// @tparam ListT The @c TypeList
42 /// @tparam Idx The index of the type to get
43 template<typename ListT, size_t Idx, typename = void> struct TSGetElementImpl;
44 
45 /// @brief Partial specialization for valid (in range) index queries.
46 /// @tparam Ts Unpacked types from a @c TypeList
47 /// @tparam Idx The index of the type to get
48 template<typename... Ts, size_t Idx>
49 struct TSGetElementImpl<TypeList<Ts...>, Idx,
50  typename std::enable_if<(Idx < sizeof...(Ts) && sizeof...(Ts))>::type> {
51  using type = typename std::tuple_element<Idx, std::tuple<Ts...>>::type;
52 };
53 
54 /// @brief Partial specialization for invalid index queries (i.e. out-of-range
55 /// indices such as @c TypeList<Int32>::Get<1>). Defines the NullType.
56 /// @tparam Ts Unpacked types from a @c TypeList
57 /// @tparam Idx The index of the type to get
58 template<typename... Ts, size_t Idx>
59 struct TSGetElementImpl<TypeList<Ts...>, Idx,
60  typename std::enable_if<!(Idx < sizeof...(Ts) && sizeof...(Ts))>::type> {
61  using type = NullType;
62 };
63 
64 
65 /// @brief Search for a given type within a @c TypeList.
66 /// @details If the type is found, a @c bool constant @c Value is set to true
67 /// and an @c int64_t @c Index points to the location of the type. If
68 /// multiple versions of the types exist, the value of @c Index is
69 /// always the location of the first matching type. If the type is not
70 /// found, @c Value is set to false and @c Index is set to -1.
71 /// @note This implementation is recursively defined until the type is found
72 /// or until the end of the list is reached. The last template argument
73 /// is used as an internal counter to track the current index being
74 /// evaluated.
75 /// @tparam ListT The @c TypeList
76 /// @tparam T The type to find
77 template <typename ListT, typename T, size_t=0>
78 struct TSHasTypeImpl;
79 
80 /// @brief Partial specialization on an empty @c TypeList, instantiated when
81 /// @c TSHasTypeImpl has been invoked with an empty @c TypeList or when
82 /// a recursive search reaches the end of a @c TypeList.
83 /// @tparam T The type to find
84 /// @tparam Idx Current index
85 template <typename T, size_t Idx>
86 struct TSHasTypeImpl<TypeList<>, T, Idx> {
87  static constexpr bool Value = false;
88  static constexpr int64_t Index = -1;
89 };
90 
91 /// @brief Partial specialization on a @c TypeList which still contains types,
92 /// but the current type being evaluated @c U does not match the given
93 /// type @C T.
94 /// @tparam U The current type being evaluated within the @c TypeList
95 /// @tparam T The type to find
96 /// @tparam Ts Remaining types
97 /// @tparam Idx Current index
98 template <typename U, typename T, typename... Ts, size_t Idx>
99 struct TSHasTypeImpl<TypeList<U, Ts...>, T, Idx> :
100  TSHasTypeImpl<TypeList<Ts...>, T, Idx+1> {};
101 
102 /// @brief Partial specialization on a @c TypeList where @c T matches the
103 /// current type (i.e. the type has been found).
104 /// @tparam T The type to find
105 /// @tparam Ts Remaining types
106 /// @tparam Idx Current index
107 template <typename T, typename... Ts, size_t Idx>
108 struct TSHasTypeImpl<TypeList<T, Ts...>, T, Idx>
109 {
110  static constexpr bool Value = true;
111  static constexpr int64_t Index = static_cast<int64_t>(Idx);
112 };
113 
114 
115 /// @brief Remove any duplicate types from a @c TypeList.
116 /// @details This implementation effectively rebuilds a @c TypeList by starting
117 /// with an empty @c TypeList and recursively defining an expanded
118 /// @c TypeList for every type (first to last), only if the type does
119 /// not already exist in the new @c TypeList. This has the effect of
120 /// dropping all but the first of duplicate types.
121 /// @note Each type must define a new instantiation of this object.
122 /// @tparam ListT The starting @c TypeList, usually (but not limited to) an
123 /// empty @c TypeList
124 /// @tparam Ts The list of types to make unique
125 template <typename ListT, typename... Ts>
126 struct TSMakeUniqueImpl {
127  using type = ListT;
128 };
129 
130 /// @brief Partial specialization for type packs, where by the next type @c U
131 /// is checked in the existing type set @c Ts for duplication. If the
132 /// type does not exist, it is added to the new @c TypeList definition,
133 /// otherwise it is dropped. In either case, this class is recursively
134 /// defined with the remaining types @c Us.
135 /// @tparam Ts Current types in the @c TypeList
136 /// @tparam U Type to check for duplication in @c Ts
137 /// @tparam Us Remaining types
138 template <typename... Ts, typename U, typename... Us>
139 struct TSMakeUniqueImpl<TypeList<Ts...>, U, Us...>
140 {
141  using type = typename std::conditional<
142  TSHasTypeImpl<TypeList<Ts...>, U>::Value,
143  typename TSMakeUniqueImpl<TypeList<Ts...>, Us...>::type,
144  typename TSMakeUniqueImpl<TypeList<Ts..., U>, Us...>::type >::type;
145 };
146 
147 
148 /// @brief Append any number of types to a @c TypeList
149 /// @details Defines a new @c TypeList with the provided types appended
150 /// @tparam ListT The @c TypeList to append to
151 /// @tparam Ts Types to append
152 template<typename ListT, typename... Ts> struct TSAppendImpl;
153 
154 /// @brief Partial specialization for a @c TypeList with a list of zero or more
155 /// types to append
156 /// @tparam Ts Current types within the @c TypeList
157 /// @tparam OtherTs Other types to append
158 template<typename... Ts, typename... OtherTs>
159 struct TSAppendImpl<TypeList<Ts...>, OtherTs...> {
160  using type = TypeList<Ts..., OtherTs...>;
161 };
162 
163 /// @brief Partial specialization for a @c TypeList with another @c TypeList.
164 /// Appends the other TypeList's members.
165 /// @tparam Ts Types within the first @c TypeList
166 /// @tparam OtherTs Types within the second @c TypeList
167 template<typename... Ts, typename... OtherTs>
168 struct TSAppendImpl<TypeList<Ts...>, TypeList<OtherTs...>> {
169  using type = TypeList<Ts..., OtherTs...>;
170 };
171 
172 
173 /// @brief Remove all occurrences of type T from a @c TypeList
174 /// @details Defines a new @c TypeList with the provided types removed
175 /// @tparam ListT The @c TypeList
176 /// @tparam T Type to remove
177 template<typename ListT, typename T> struct TSEraseImpl;
178 
179 /// @brief Partial specialization for an empty @c TypeList
180 /// @tparam T Type to remove, has no effect
181 template<typename T>
182 struct TSEraseImpl<TypeList<>, T> { using type = TypeList<>; };
183 
184 /// @brief Partial specialization where the currently evaluating type in a
185 /// @c TypeList matches the type to remove. Recursively defines this
186 /// implementation with the remaining types.
187 /// @tparam Ts Unpacked types within the @c TypeList
188 /// @tparam T Type to remove
189 template<typename... Ts, typename T>
190 struct TSEraseImpl<TypeList<T, Ts...>, T> {
191  using type = typename TSEraseImpl<TypeList<Ts...>, T>::type;
192 };
193 
194 /// @brief Partial specialization where the currently evaluating type @c T2 in
195 /// a @c TypeList does not match the type to remove @c T. Recursively
196 /// defines this implementation with the remaining types.
197 /// @tparam T2 Current type within the @c TypeList, which does not match @c T
198 /// @tparam Ts Other types within the @c TypeList
199 /// @tparam T Type to remove
200 template<typename T2, typename... Ts, typename T>
201 struct TSEraseImpl<TypeList<T2, Ts...>, T> {
202  using type = typename TSAppendImpl<TypeList<T2>,
203  typename TSEraseImpl<TypeList<Ts...>, T>::type>::type;
204 };
205 
206 /// @brief Front end implementation to call TSEraseImpl which removes all
207 /// occurrences of a type from a @c TypeList. This struct handles the
208 /// case where the type to remove is another @c TypeList, in which case
209 /// all types in the second @c TypeList are removed from the first.
210 /// @tparam ListT The @c TypeList
211 /// @tparam Ts Types in the @c TypeList
212 template<typename ListT, typename... Ts> struct TSRemoveImpl;
213 
214 /// @brief Partial specialization when there are no types in the @c TypeList.
215 /// @tparam ListT The @c TypeList
216 template<typename ListT>
217 struct TSRemoveImpl<ListT> { using type = ListT; };
218 
219 /// @brief Partial specialization when the type to remove @c T is not another
220 /// @c TypeList. @c T is removed from the @c TypeList.
221 /// @tparam ListT The @c TypeList
222 /// @tparam T Type to remove
223 /// @tparam Ts Types in the @c TypeList
224 template<typename ListT, typename T, typename... Ts>
225 struct TSRemoveImpl<ListT, T, Ts...> {
227 };
228 
229 /// @brief Partial specialization when the type to remove is another
230 /// @c TypeList. All types within the other type list are removed from
231 /// the first list.
232 /// @tparam ListT The @c TypeList
233 /// @tparam Ts Types from the second @c TypeList to remove from the first
234 template<typename ListT, typename... Ts>
235 struct TSRemoveImpl<ListT, TypeList<Ts...>> {
236  using type = typename TSRemoveImpl<ListT, Ts...>::type;
237 };
238 
239 /// @brief Remove the first element of a type list. If the list is empty,
240 /// nothing is done. This base configuration handles the empty list.
241 /// @note Much cheaper to instantiate than TSRemoveIndicesImpl
242 /// @tparam T The @c TypeList
243 template<typename T>
244 struct TSRemoveFirstImpl {
245  using type = TypeList<>;
246 };
247 
248 /// @brief Partial specialization for removing the first type of a @c TypeList
249 /// when the list is not empty i.e. does that actual work.
250 /// @tparam T The first type in the @c TypeList.
251 /// @tparam Ts Remaining types in the @c TypeList
252 template<typename T, typename... Ts>
253 struct TSRemoveFirstImpl<TypeList<T, Ts...>> {
254  using type = TypeList<Ts...>;
255 };
256 
257 
258 /// @brief Remove the last element of a type list. If the list is empty,
259 /// nothing is done. This base configuration handles the empty list.
260 /// @note Cheaper to instantiate than TSRemoveIndicesImpl
261 /// @tparam T The @c TypeList
262 template<typename T>
263 struct TSRemoveLastImpl { using type = TypeList<>; };
264 
265 /// @brief Partial specialization for removing the last type of a @c TypeList.
266 /// This instance is instantiated when the @c TypeList contains a
267 /// single type, or the primary struct which recursively removes types
268 /// (see below) hits the last type. Evaluates the last type to the empty
269 /// list (see above).
270 /// @tparam T The last type in the @c TypeList
271 template<typename T>
272 struct TSRemoveLastImpl<TypeList<T>> : TSRemoveLastImpl<T> {};
273 
274 /// @brief Partial specialization for removing the last type of a @c TypeList
275 /// with a type list size of two or more. Recursively defines this
276 /// implementation with the remaining types, effectively rebuilding the
277 /// @c TypeList until the last type is hit, which is dropped.
278 /// @tparam T The current type in the @c TypeList
279 /// @tparam Ts Remaining types in the @c TypeList
280 template<typename T, typename... Ts>
281 struct TSRemoveLastImpl<TypeList<T, Ts...>>
282 {
283  using type =
284  typename TypeList<T>::template
285  Append<typename TSRemoveLastImpl<TypeList<Ts...>>::type>;
286 };
287 
288 
289 /// @brief Remove a number of types from a @c TypeList based on a @c First and
290 /// @c Last index.
291 /// @details Both indices are inclusive, such that when <tt>First == Last</tt>
292 /// a single type is removed (assuming the index exists). If
293 /// <tt>Last < First</tt>, nothing is done. Any indices which do not
294 /// exist are ignored. If @c Last is greater than the number of types
295 /// in the @c TypeList, all types from @c First to the end of the list
296 /// are dropped.
297 /// @tparam ListT The @c TypeList
298 /// @tparam First The first index
299 /// @tparam Last The last index
300 /// @tparam Idx Internal counter for the current index
301 template<typename ListT, size_t First, size_t Last, size_t Idx=0>
302 struct TSRemoveIndicesImpl;
303 
304 /// @brief Partial specialization for an empty @c TypeList
305 /// @tparam First The first index
306 /// @tparam Last The last index
307 /// @tparam Idx Internal counter for the current index
308 template<size_t First, size_t Last, size_t Idx>
309 struct TSRemoveIndicesImpl<TypeList<>, First, Last, Idx> {
310  using type = TypeList<>;
311 };
312 
313 /// @brief Partial specialization for a @c TypeList containing a single element.
314 /// @tparam T The last or only type in a @c TypeList
315 /// @tparam First The first index
316 /// @tparam Last The last index
317 /// @tparam Idx Internal counter for the current index
318 template<typename T, size_t First, size_t Last, size_t Idx>
319 struct TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>
320 {
321 private:
322  static constexpr bool Remove = Idx >= First && Idx <= Last;
323 public:
324  using type = typename std::conditional<Remove, TypeList<>, TypeList<T>>::type;
325 };
326 
327 /// @brief Partial specialization for a @c TypeList containing two or more types.
328 /// @details This implementation effectively rebuilds a @c TypeList by starting
329 /// with an empty @c TypeList and recursively defining an expanded
330 /// @c TypeList for every type (first to last), only if the type's
331 /// index does not fall within the range of indices defines by
332 /// @c First and @c Last. Recursively defines this implementation with
333 /// all but the last type.
334 /// @tparam T The currently evaluating type within a @c TypeList
335 /// @tparam Ts Remaining types in the @c TypeList
336 /// @tparam First The first index
337 /// @tparam Last The last index
338 /// @tparam Idx Internal counter for the current index
339 template<typename T, typename... Ts, size_t First, size_t Last, size_t Idx>
340 struct TSRemoveIndicesImpl<TypeList<T, Ts...>, First, Last, Idx>
341 {
342 private:
343  using ThisList = typename TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>::type;
344  using NextList = typename TSRemoveIndicesImpl<TypeList<Ts...>, First, Last, Idx+1>::type;
345 public:
346  using type = typename ThisList::template Append<NextList>;
347 };
348 
349 
350 template<typename OpT> inline void TSForEachImpl(OpT) {}
351 template<typename OpT, typename T, typename... Ts>
352 inline void TSForEachImpl(OpT op) { op(T()); TSForEachImpl<OpT, Ts...>(op); }
353 
354 } // namespace internal
355 
356 /// @endcond
357 
358 
359 /// @brief A list of types (not necessarily unique)
360 /// @details Example:
361 /// @code
362 /// using MyTypes = openvdb::TypeList<int, float, int, double, float>;
363 /// @endcode
364 template<typename... Ts>
365 struct TypeList
366 {
367  /// The type of this list
368  using Self = TypeList;
369 
370  /// @brief The number of types in the type list
371  static constexpr size_t Size = sizeof...(Ts);
372 
373  /// @brief Access a particular element of this type list. If the index
374  /// is out of range, typelist_internal::NullType is returned.
375  template<size_t N>
377  using Front = Get<0>;
378  using Back = Get<Size-1>;
379 
380  /// @brief True if this list contains the given type, false otherwise
381  /// @details Example:
382  /// @code
383  /// {
384  /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
385  /// using RealTypes = openvdb::TypeList<float, double>;
386  /// }
387  /// {
388  /// openvdb::TypeList<IntTypes>::Contains<Int32>; // true
389  /// openvdb::TypeList<RealTypes>::Contains<Int32>; // false
390  /// }
391  /// @endcode
392  template<typename T>
393  static constexpr bool Contains = typelist_internal::TSHasTypeImpl<Self, T>::Value;
394 
395  /// @brief Returns the index of the first found element of the given type, -1 if
396  /// no matching element exists.
397  /// @details Example:
398  /// @code
399  /// {
400  /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
401  /// using RealTypes = openvdb::TypeList<float, double>;
402  /// }
403  /// {
404  /// const int64_t L1 = openvdb::TypeList<IntTypes>::Index<Int32>; // 1
405  /// const int64_t L2 = openvdb::TypeList<RealTypes>::Index<Int32>; // -1
406  /// }
407  /// @endcode
408  template<typename T>
410 
411  /// @brief Remove any duplicate types from this TypeList by rotating the
412  /// next valid type left (maintains the order of other types). Optionally
413  /// combine the result with another TypeList.
414  /// @details Example:
415  /// @code
416  /// {
417  /// using Types = openvdb::TypeList<Int16, Int32, Int16, float, float, Int64>;
418  /// }
419  /// {
420  /// using UniqueTypes = Types::Unique<>; // <Int16, Int32, float, Int64>
421  /// }
422  /// @endcode
423  template<typename ListT = TypeList<>>
424  using Unique = typename typelist_internal::TSMakeUniqueImpl<ListT, Ts...>::type;
425 
426  /// @brief Append types, or the members of another TypeList, to this list.
427  /// @details Example:
428  /// @code
429  /// {
430  /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
431  /// using RealTypes = openvdb::TypeList<float, double>;
432  /// using NumericTypes = IntTypes::Append<RealTypes>;
433  /// }
434  /// {
435  /// using IntTypes = openvdb::TypeList<Int16>::Append<Int32, Int64>;
436  /// using NumericTypes = IntTypes::Append<float>::Append<double>;
437  /// }
438  /// @endcode
439  template<typename... TypesToAppend>
440  using Append = typename typelist_internal::TSAppendImpl<Self, TypesToAppend...>::type;
441 
442  /// @brief Remove all occurrences of one or more types, or the members of
443  /// another TypeList, from this list.
444  /// @details Example:
445  /// @code
446  /// {
447  /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>;
448  /// using LongTypes = openvdb::TypeList<Int64, double>;
449  /// using ShortTypes = NumericTypes::Remove<LongTypes>; // float, Int16, Int32
450  /// }
451  /// @endcode
452  template<typename... TypesToRemove>
453  using Remove = typename typelist_internal::TSRemoveImpl<Self, TypesToRemove...>::type;
454 
455  /// @brief Remove the first element of this type list. Has no effect if the
456  /// type list is already empty.
457  /// @details Example:
458  /// @code
459  /// {
460  /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
461  /// using EmptyTypes = openvdb::TypeList<>;
462  /// }
463  /// {
464  /// IntTypes::PopFront; // openvdb::TypeList<Int32, Int64>;
465  /// EmptyTypes::PopFront; // openvdb::TypeList<>;
466  /// }
467  /// @endcode
469 
470  /// @brief Remove the last element of this type list. Has no effect if the
471  /// type list is already empty.
472  /// @details Example:
473  /// @code
474  /// {
475  /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
476  /// using EmptyTypes = openvdb::TypeList<>;
477  /// }
478  /// {
479  /// IntTypes::PopBack; // openvdb::TypeList<Int16, Int32>;
480  /// EmptyTypes::PopBack; // openvdb::TypeList<>;
481  /// }
482  /// @endcode
484 
485  /// @brief Return a new list with types removed by their location within the list.
486  /// If First is equal to Last, a single element is removed (if it exists).
487  /// If First is greater than Last, the list remains unmodified.
488  /// @details Example:
489  /// @code
490  /// {
491  /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>;
492  /// }
493  /// {
494  /// using IntTypes = NumericTypes::RemoveByIndex<0,1>; // openvdb::TypeList<Int16, Int32, Int64>;
495  /// using RealTypes = NumericTypes::RemoveByIndex<2,4>; // openvdb::TypeList<float, double>;
496  /// using RemoveFloat = NumericTypes::RemoveByIndex<0,0>; // openvdb::TypeList<double, Int16, Int32, Int64>;
497  /// }
498  /// @endcode
499  template <size_t First, size_t Last>
501 
502  /// @brief Invoke a templated, unary functor on a value of each type in this list.
503  /// @details Example:
504  /// @code
505  /// #include <typeinfo>
506  ///
507  /// template<typename ListT>
508  /// void printTypeList()
509  /// {
510  /// std::string sep;
511  /// auto op = [&](auto x) { // C++14
512  /// std::cout << sep << typeid(decltype(x)).name(); sep = ", "; };
513  /// ListT::foreach(op);
514  /// }
515  ///
516  /// using MyTypes = openvdb::TypeList<int, float, double>;
517  /// printTypeList<MyTypes>(); // "i, f, d" (exact output is compiler-dependent)
518  /// @endcode
519  ///
520  /// @note The functor object is passed by value. Wrap it with @c std::ref
521  /// to use the same object for each type.
522  template<typename OpT>
523  static void foreach(OpT op) { typelist_internal::TSForEachImpl<OpT, Ts...>(op); }
524 };
525 
526 
527 } // namespace OPENVDB_VERSION_NAME
528 } // namespace openvdb
529 
530 
531 #endif // OPENVDB_TYPELIST_HAS_BEEN_INCLUDED
static constexpr bool Contains
True if this list contains the given type, false otherwise.
Definition: TypeList.h:393
typename typelist_internal::TSRemoveFirstImpl< Self >::type PopFront
Remove the first element of this type list. Has no effect if the type list is already empty...
Definition: TypeList.h:468
typename typelist_internal::TSAppendImpl< Self, TypesToAppend...>::type Append
Append types, or the members of another TypeList, to this list.
Definition: TypeList.h:440
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:167
typename typelist_internal::TSMakeUniqueImpl< ListT, Ts...>::type Unique
Remove any duplicate types from this TypeList by rotating the next valid type left (maintains the ord...
Definition: TypeList.h:424
Mark the end – don't use this!
typename typelist_internal::TSRemoveImpl< Self, TypesToRemove...>::type Remove
Remove all occurrences of one or more types, or the members of another TypeList, from this list...
Definition: TypeList.h:453
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1253
typename typelist_internal::TSRemoveIndicesImpl< Self, First, Last >::type RemoveByIndex
Return a new list with types removed by their location within the list. If First is equal to Last...
Definition: TypeList.h:500
TypeList Self
The type of this list.
Definition: TypeList.h:368
Library and file format version numbers.
typename typelist_internal::TSGetElementImpl< Self, N >::type Get
Access a particular element of this type list. If the index is out of range, typelist_internal::NullT...
Definition: TypeList.h:376
typename typelist_internal::TSRemoveLastImpl< Self >::type PopBack
Remove the last element of this type list. Has no effect if the type list is already empty...
Definition: TypeList.h:483
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:113
A list of types (not necessarily unique)
Definition: TypeList.h:365
static constexpr size_t Size
The number of types in the type list.
Definition: TypeList.h:371
type
Definition: core.h:528