Drake
type_pack.h
Go to the documentation of this file.
1 #pragma once
2 
3 /// @file
4 /// Basic meta-programming utilities for types, focused on template parameter
5 /// packs.
6 
7 #include <cstddef>
8 #include <type_traits>
9 #include <typeindex>
10 #include <typeinfo>
11 #include <utility>
12 
13 namespace drake {
14 
15 template <typename ... Ts>
16 struct type_pack;
17 
18 namespace detail {
19 
20 // Provides type at given index.
21 template <size_t N, size_t K, typename T, typename ... Ts>
22 struct type_at_impl {
23  using type = typename type_at_impl<N, K + 1, Ts...>::type;
24 };
25 
26 // Base case.
27 template <size_t N, typename T, typename ... Ts>
28 struct type_at_impl<N, N, T, Ts...> {
29  using type = T;
30 };
31 
32 // Visits a type given a VisitWith mechanism, templated to permit
33 // conditional execution.
34 template <typename VisitWith, typename Visitor>
36  template <typename T, bool execute>
37  struct runner {
38  inline static void run(Visitor&& visitor) {
39  VisitWith::template run<T>(std::forward<Visitor>(visitor));
40  }
41  };
42  template <typename T>
43  struct runner<T, false> {
44  inline static void run(Visitor&&) {}
45  };
46 };
47 
48 // Catches non-template types explicitly.
49 template <typename T>
51  // Defer to show that this is a bad instantiation.
52  static_assert(!std::is_same<T, T>::value, "Wrong template");
53 };
54 
55 template <template <typename ... Ts> class Tpl, typename ... Ts>
56 struct type_pack_extract_impl<Tpl<Ts...>> {
57  using type = type_pack<Ts...>;
58 };
59 
60 // Provides type for pack expansion into an initializer list for
61 // deterministic execution order.
62 using DummyList = bool[];
63 
64 template <typename T>
67  "Must be default constructible");
68 };
69 
70 } // namespace detail
71 
72 
73 /// Extracts the Ith type from a sequence of types.
74 template <size_t I, typename ... Ts>
75 struct type_at {
76  static_assert(I >= 0 && I < sizeof...(Ts), "Invalid type index");
77  using type = typename detail::type_at_impl<I, 0, Ts...>::type;
78 };
79 
80 /// Provides a tag to pass a type for ease of inference.
81 template <typename T>
82 struct type_tag {
83  using type = T;
84 };
85 
86 /// Provides a tag for single-parameter templates.
87 /// @note Single-parameter is specialized because `using` aliases are picky
88 /// about how template parameters are passed.
89 /// @see https://stackoverflow.com/a/33131008/7829525
90 /// @note The above issues can be worked around if either (a) inheritance
91 /// rather than aliasing is used, or (b) the alias uses the *exact* matching
92 /// form of expansion.
93 template <template <typename> class Tpl>
95  template <typename T>
96  using type = Tpl<T>;
97 };
98 
99 /// Provides a tag to pass a parameter packs for ease of inference.
100 template <typename ... Ts>
101 struct type_pack {
102  /// Number of template parameters.
103  static constexpr int size = sizeof...(Ts);
104 
105  /// Rebinds parameter pack to a given template.
106  template <template <typename...> class Tpl>
107  using bind = Tpl<Ts...>;
108 
109  /// Extracts the Ith type from this sequence.
110  template <size_t I>
111  using type_at = typename drake::type_at<I, Ts...>::type;
112 };
113 
114 /// Returns an expression (only to be used in `decltype`) for inferring
115 /// and binding a parameter pack to a template.
116 template <template <typename...> class Tpl, typename ... Ts>
117 Tpl<Ts...> type_bind(type_pack<Ts...>);
118 
119 /// Extracts the inner template arguments (typename only) for a typename which
120 /// is a template instantiation.
121 template <typename T>
123 
124 /// Visit a type by constructing its default value.
125 /// Useful for iterating over `type_tag`, `type_pack`, `std::integral_constant`,
126 /// etc.
128  template <typename T, typename Visitor>
129  inline static void run(Visitor&& visitor) {
130  // TODO(eric.cousineau): Figure out how to make this the only error, without
131  // wasting more function calls.
133  visitor(T{});
134  }
135 };
136 
137 /// Visits a type by construct a template tag's default value.
138 template <template <typename> class Tag = type_tag>
140  template <typename T, typename Visitor>
141  inline static void run(Visitor&& visitor) {
142  visitor(Tag<T>{});
143  }
144 };
145 
146 /// Provides a check which will return true for any type.
147 template <typename T>
148 using type_check_always_true = std::true_type;
149 
150 /// Provides backport of C++17 `std::negation`.
151 // TODO(eric.cousineau): Remove this once C++17 is used.
152 template <typename T>
153 using negation = std::integral_constant<bool, !T::value>;
154 
155 /// Provides a check which returns whether `T` is different than `U`.
156 template <typename T>
158  template <typename U>
160 };
161 
162 /// Visits each type in a type pack.
163 /// @tparam VisitWith
164 /// Visit helper. @see `type_visit_with_default`, `type_visit_with_tag`.
165 /// @tparam Predicate Predicate operating on the type dictated by `VisitWith`.
166 /// @param visitor Lambda or functor for visiting a type.
167 template <class VisitWith = type_visit_with_default,
168  template <typename> class Predicate = type_check_always_true,
169  typename Visitor = void,
170  typename ... Ts>
172  Visitor&& visitor, type_pack<Ts...> = {},
174  (void)detail::DummyList{(
177  run(std::forward<Visitor>(visitor)),
178  true)...};
179 }
180 
181 /// Provides short-hand for hashing a type.
182 template <typename T>
183 constexpr size_t type_hash() {
184  return std::type_index(typeid(T)).hash_code();
185 }
186 
187 } // namespace drake
Provides a tag for single-parameter templates.
Definition: type_pack.h:94
typename detail::type_at_impl< I, 0, Ts... >::type type
Definition: type_pack.h:77
double T
Definition: lifetime_test_util_py.cc:14
Definition: automotive_demo.cc:89
Tpl< T > type
Definition: type_pack.h:96
bool[] DummyList
Definition: type_pack.h:62
negation< std::is_same< T, U >> type
Definition: type_pack.h:159
void type_visit(Visitor &&visitor, type_pack< Ts... >={}, template_single_tag< Predicate >={})
Visits each type in a type pack.
Definition: type_pack.h:171
Provides a tag to pass a type for ease of inference.
Definition: type_pack.h:82
Extracts the Ith type from a sequence of types.
Definition: type_pack.h:75
static void run(Visitor &&visitor)
Definition: type_pack.h:38
static void run(Visitor &&)
Definition: type_pack.h:44
Provides a tag to pass a parameter packs for ease of inference.
Definition: type_pack.h:16
typename drake::type_at< I, Ts... >::type type_at
Extracts the Ith type from this sequence.
Definition: type_pack.h:111
int value
Definition: copyable_unique_ptr_test.cc:61
Definition: type_pack.h:50
std::integral_constant< bool,!T::value > negation
Provides backport of C++17 std::negation.
Definition: type_pack.h:153
Tpl< Ts... > bind
Rebinds parameter pack to a given template.
Definition: type_pack.h:107
std::true_type type_check_always_true
Provides a check which will return true for any type.
Definition: type_pack.h:148
Definition: type_pack.h:35
static void run(Visitor &&visitor)
Definition: type_pack.h:129
static void run(Visitor &&visitor)
Definition: type_pack.h:141
Tpl< Ts... > type_bind(type_pack< Ts... >)
Returns an expression (only to be used in decltype) for inferring and binding a parameter pack to a t...
Provides a check which returns whether T is different than U.
Definition: type_pack.h:157
typename detail::type_pack_extract_impl< T >::type type_pack_extract
Extracts the inner template arguments (typename only) for a typename which is a template instantiatio...
Definition: type_pack.h:122
Visits a type by construct a template tag&#39;s default value.
Definition: type_pack.h:139
constexpr size_t type_hash()
Provides short-hand for hashing a type.
Definition: type_pack.h:183
Definition: type_pack.h:37
Visit a type by constructing its default value.
Definition: type_pack.h:127
typename type_at_impl< N, K+1, Ts... >::type type
Definition: type_pack.h:23
Definition: type_pack.h:22