ZeroErr
Loading...
Searching...
No Matches
typetraits.h
Go to the documentation of this file.
1#pragma once
3
4#include <ostream>
5#include <sstream>
6#include <string>
7#include <tuple> // this should be removed
8#include <type_traits>
9#include <complex>
10#include <memory>
11
13
14
15namespace zeroerr {
16
17
31template <unsigned N>
32struct rank : rank<N - 1> {};
33template <>
34struct rank<0> {};
35
36
37namespace detail {
38
39// C++11 void_t
40template <typename... Ts>
41using void_t = void;
42
43// Type dependent "true"/"false".
44// Useful for SFINAE and static_asserts where we need a type dependent
45// expression that happens to be constant.
46template <typename T>
48 static std::false_type value;
49};
50
51template <typename T>
53 static std::true_type value;
54};
55
56
57// Generate sequence of integers from 0 to N-1
58// Usage: detail::gen_seq<N> then use <size_t... I> to match it
59template <unsigned...>
60struct seq {};
61
62template <unsigned N, unsigned... Is>
63struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
64
65template <unsigned... Is>
66struct gen_seq<0, Is...> : seq<Is...> {};
67
68
69// Some utility structs to check template specialization
70template <typename Test, template <typename...> class Ref>
71struct is_specialization : std::false_type {};
72
73template <template <typename...> class Ref, typename... Args>
74struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
75
76
77// Check if a type is stream writable, i.e., std::cout << foo;
78// Usage: is_streamable<std::ostream, int>::value
79template <typename S, typename T>
81
82template <typename S, typename T, typename = void>
83struct is_streamable : std::false_type {};
84
85template <typename S, typename T>
86struct is_streamable<S, T, has_stream_operator<S, T>> : std::true_type {};
87
88
89// Check if a type is a container type
90// Usage: is_container<std::vector<int>>::value
91template <typename T>
93 void_t<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>;
94
95template <typename T, typename = void>
96struct is_container : std::false_type {};
97
98template <typename T>
99struct is_container<T, has_begin_end<T>> : std::true_type {};
100
101
102template <typename T>
104 void_t<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end()),
105 decltype(std::declval<T>().find(std::declval<typename T::key_type>())),
106 decltype(std::declval<T>().insert(std::declval<typename T::value_type>()))>;
107
108template <typename T, typename = void>
109struct is_associative_container : std::false_type {};
110
111template <typename T>
112struct is_associative_container<T, has_begin_end_find_insert<T>> : std::true_type {};
113
114
115#if ZEROERR_CXX_STANDARD >= 17
116#define ZEROERR_STRING_VIEW std::is_same<T, std::string_view>::value
117#else
118#define ZEROERR_STRING_VIEW 0
119#endif
120
121// Check if a type is a string type
122template <class T>
124 : std::integral_constant<bool, std::is_same<T, std::string>::value ||
125 std::is_same<T, const char*>::value || ZEROERR_STRING_VIEW> {
126};
127
128
129// Completeness check that SFINAE-fails for incomplete T.
130template <typename T, typename = void>
131struct is_complete_type : std::false_type {};
132template <typename T>
133struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
134
135// Non-pointer [0] detection. Must not be instantiated for pointer-to-incomplete:
136// GCC treats that subscript as a hard error inside void_t, not SFINAE.
137template <typename T, typename = void>
138struct is_indexable_non_pointer : std::false_type {};
139template <typename T>
140struct is_indexable_non_pointer<T, void_t<decltype(std::declval<T>()[0])>> : std::true_type {};
141
142// Dispatch on is_pointer first so pointer-to-incomplete never reaches [0].
143template <typename T,
144 bool = std::is_pointer<
145 typename std::remove_cv<typename std::remove_reference<T>::type>::type>::value>
147
148template <typename T>
149struct is_array_dispatch<T, true>
150 : is_complete_type<typename std::remove_pointer<
151 typename std::remove_cv<typename std::remove_reference<T>::type>::type>::type> {};
152
153// Check if a type can use arr[0] like an array.
154template <typename T>
156
157
158template <typename T, typename = void>
159struct is_modifiable : std::false_type {};
160
161template <typename T>
162struct is_modifiable<T, void_t<decltype(
163 // Iterable
164 T().begin(), T().end(), T().size(),
165 // Values are mutable
166 // This rejects associative containers, for example
167 // *T().begin() = std::declval<value_type_t<T>>(),
168 // Can insert and erase elements
169 T().insert(T().end(), std::declval<typename T::value_type>()),
170 T().erase(T().begin()), (void)0)>> : std::true_type {};
171
172
173
174// Check if a type has the element type as std::pair
175template <typename T>
178 decltype(std::declval<typename T::value_type>().second)>;
179template <typename T, typename = void>
180struct ele_type_is_pair : std::false_type {};
181
182template <typename T>
183struct ele_type_is_pair<T, has_pair_type<T>> : std::true_type {};
184
185template <typename T, typename V = void>
187 using type = T;
188};
189
190template <>
191struct to_store_type<const char*> {
192 using type = std::string;
193};
194
195template <>
196struct to_store_type<const char (&)[]> {
197 using type = std::string;
198};
199
200template <typename T>
201using is_not_array = typename std::enable_if<!std::is_array<T>::value>::type;
202template <typename T>
204 using type = T;
205};
206
207template <typename T>
208struct to_store_type<T&&> {
209 using type = T;
210};
211
212template <typename T>
214
215
216template <size_t I>
218 template <typename T, typename F>
219 static void visit(T& tup, size_t idx, F&& fun) {
220 if (idx == I - 1)
221 fun(std::get<I - 1>(tup));
222 else
223 visit_impl<I - 1>::visit(tup, idx, std::forward<F>(fun));
224 }
225};
226
227template <>
228struct visit_impl<0> {
229 template <typename T, typename F>
230 static void visit(T&, size_t, F&&) {}
231};
232
233template <typename F, typename... Ts>
234void visit_at(const std::tuple<Ts...>& tup, size_t idx, F&& fun) {
235 visit_impl<sizeof...(Ts)>::visit(tup, idx, std::forward<F>(fun));
236}
237
238template <typename F, typename... Ts>
239void visit_at(std::tuple<Ts...>& tup, size_t idx, F&& fun) {
240 visit_impl<sizeof...(Ts)>::visit(tup, idx, std::forward<F>(fun));
241}
242
243
244template <size_t I>
246 template <typename T1, typename T2, typename F>
247 static void visit(T1 tup1, T2 tup2, size_t idx, F&& fun) {
248 if (idx == I - 1)
249 fun(std::get<I - 1>(tup1), std::get<I - 1>(tup2));
250 else
251 visit2_impl<I - 1>::visit(tup1, tup2, idx, std::forward<F>(fun));
252 }
253};
254
255template <>
256struct visit2_impl<0> {
257 template <typename T1, typename T2, typename F>
258 static void visit(T1&, T2&, size_t, F&&) {}
259};
260
261template <typename F, typename... Ts, typename... T2s>
262void visit2_at(const std::tuple<Ts...>& tup1, const std::tuple<T2s...>& tup2, size_t idx, F&& fun) {
263 visit2_impl<sizeof...(Ts)>::visit(tup1, tup2, idx, std::forward<F>(fun));
264}
265
266template <typename F, typename... Ts, typename... T2s>
267void visit2_at(std::tuple<Ts...>& tup1, std::tuple<T2s...>& tup2, size_t idx, F&& fun) {
268 visit2_impl<sizeof...(Ts)>::visit(tup1, tup2, idx, std::forward<F>(fun));
269}
270
271template <typename F, typename... Ts, typename... T2s>
272void visit2_at(const std::tuple<Ts...>& tup1, std::tuple<T2s...>& tup2, size_t idx, F&& fun) {
273 visit2_impl<sizeof...(Ts)>::visit(tup1, tup2, idx, std::forward<F>(fun));
274}
275
276template <typename F, typename... Ts, typename... T2s>
277void visit2_at(std::tuple<Ts...>& tup1, const std::tuple<T2s...>& tup2, size_t idx, F&& fun) {
278 visit2_impl<sizeof...(Ts)>::visit(tup1, tup2, idx, std::forward<F>(fun));
279}
280
281#define ZEROERR_ENABLE_IF(x) \
282 template <typename T> \
283 typename std::enable_if<x, void>::type
284#define ZEROERR_IS_INT std::is_integral<T>::value
285#define ZEROERR_IS_FLOAT std::is_floating_point<T>::value
286#define ZEROERR_IS_ENUM std::is_enum<T>::value
287#define ZEROERR_IS_CONTAINER detail::is_container<T>::value
288#define ZEROERR_IS_STRING detail::is_string<T>::value
289#define ZEROERR_IS_POINTER (std::is_pointer<T>::value || std::is_same<T, std::nullptr_t>::value)
290#define ZEROERR_IS_CHAR std::is_same<T, char>::value
291#define ZEROERR_IS_WCHAR std::is_same<T, wchar_t>::value
292#define ZEROERR_IS_CLASS std::is_class<T>::value
293#define ZEROERR_IS_STREAMABLE detail::is_streamable<std::ostream, T>::value
294#define ZEROERR_IS_ARRAY detail::is_array<T>::value
295#define ZEROERR_IS_COMPLEX detail::is_specialization<T, std::complex>::value
296#define ZEROERR_IS_BOOL std::is_same<T, bool>::value
297#define ZEROERR_IS_AUTOPTR \
298 (detail::is_specialization<T, std::unique_ptr>::value || \
299 detail::is_specialization<T, std::shared_ptr>::value || \
300 detail::is_specialization<T, std::weak_ptr>::value)
301#define ZEROERR_IS_MAP detail::ele_type_is_pair<T>::value
302#define ZEROERR_IS_POD std::is_standard_layout<T>::value
303#define ZEROERR_IS_EXT detail::has_extension<T>::value
304
305} // namespace detail
306
307} // namespace zeroerr
308
309
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_POP
Definition config.h:272
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_PUSH
Definition config.h:224
void_t< typename T::value_type, decltype(std::declval< typename T::value_type >().first), decltype(std::declval< typename T::value_type >().second)> has_pair_type
Definition typetraits.h:178
typename to_store_type< T >::type to_store_type_t
Definition typetraits.h:213
void_t< decltype(std::declval< S & >()<< std::declval< T >())> has_stream_operator
Definition typetraits.h:80
void_t< decltype(std::declval< T >().begin()), decltype(std::declval< T >().end()), decltype(std::declval< T >().find(std::declval< typename T::key_type >())), decltype(std::declval< T >().insert(std::declval< typename T::value_type >()))> has_begin_end_find_insert
Definition typetraits.h:106
void_t< decltype(std::declval< T >().begin()), decltype(std::declval< T >().end())> has_begin_end
Definition typetraits.h:93
void void_t
Definition typetraits.h:41
typename std::enable_if<!std::is_array< T >::value >::type is_not_array
Definition typetraits.h:201
void visit_at(const std::tuple< Ts... > &tup, size_t idx, F &&fun)
Definition typetraits.h:234
void visit2_at(const std::tuple< Ts... > &tup1, const std::tuple< T2s... > &tup2, size_t idx, F &&fun)
Definition typetraits.h:262
Definition benchmark.cpp:17
Definition typetraits.h:47
static std::false_type value
Definition typetraits.h:48
Definition typetraits.h:52
static std::true_type value
Definition typetraits.h:53
Definition typetraits.h:180
Definition typetraits.h:63
Definition typetraits.h:146
Definition typetraits.h:155
Definition typetraits.h:131
Definition typetraits.h:96
Definition typetraits.h:159
Definition typetraits.h:71
Definition typetraits.h:83
Definition typetraits.h:125
Definition typetraits.h:60
T type
Definition typetraits.h:209
std::string type
Definition typetraits.h:192
std::string type
Definition typetraits.h:197
Definition typetraits.h:186
T type
Definition typetraits.h:187
static void visit(T1 &, T2 &, size_t, F &&)
Definition typetraits.h:258
Definition typetraits.h:245
static void visit(T1 tup1, T2 tup2, size_t idx, F &&fun)
Definition typetraits.h:247
static void visit(T &, size_t, F &&)
Definition typetraits.h:230
Definition typetraits.h:217
static void visit(T &tup, size_t idx, F &&fun)
Definition typetraits.h:219
rank is a helper class for Printer to define the priority of overloaded functions.
Definition typetraits.h:32