OpenLB 1.8.1
Loading...
Searching...
No Matches
meta.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2019 Adrian Kummerlaender
4 * 2021 Adrian Kummerlaender, Nicolas Hafen, Mathias J. Krause
5 * E-mail contact: info@openlb.net
6 * The most recent release of OpenLB can be downloaded at
7 * <http://www.openlb.net/>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public
20 * License along with this program; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23*/
24
25#ifndef CORE_META_H
26#define CORE_META_H
27
28#include <type_traits>
29#include <typeindex>
30#include <tuple>
31#include <set>
32#include <utility>
33#include <string>
34#include <cstdint>
35
36// Forward-declaration of ADf type marker
37struct AD;
38
39// Define operator+ to mitigate buggy unqualified name lookup in fold expressions for Clang Versions < 12
40// see https://bugs.llvm.org/show_bug.cgi?id=30738
41#if defined __clang__ && __clang_major__ < 12
42
43namespace std {
44
46template <size_t... Is, size_t... Js>
47constexpr auto operator+(index_sequence<Is...>, index_sequence<Js...>)
48{
49 return index_sequence<Is..., Js...>();
50}
51
52}
53
54#endif
55
56namespace olb {
57
58struct ExprBase { };
59struct SimdBase { };
60
61namespace meta {
62
63// *INDENT-OFF*
64
65template <typename... TYPES> struct list;
66
68template <typename TYPE>
69bool is_aligned(const void* ptr) {
70 auto addr = reinterpret_cast<std::uintptr_t>(ptr);
71 return !(addr % alignof(TYPE));
72}
73
75
78template <typename TYPE>
79struct id {
80 using type = TYPE;
81
82 operator std::type_index() const {
83 return typeid(TYPE);
84 }
85
86 TYPE get() const {
87 return TYPE{};
88 }
89};
90
91template <typename TYPE>
92using id_t = typename id<TYPE>::type;
93
95template <auto VALUE, typename TYPE = decltype(VALUE)>
96using value = typename std::integral_constant<TYPE, VALUE>::type;
97
99template <typename T>
100std::string name() {
101 return typeid(T).name();
102}
103
105
108template <typename T>
109using is_arithmetic = typename std::integral_constant<bool,
110 std::is_base_of_v<AD,T>
111 || std::is_base_of_v<SimdBase,T>
112 || std::is_base_of_v<ExprBase,T>
113 || std::is_arithmetic_v<T>
114 // Pointers and enums are enabled for convenience
115 // TODO: Add specific arithmetic-support checking to arithmetic Vector operators
116 || std::is_pointer_v<T>
117 || std::is_enum_v<T>
118>;
119
120template <typename T, typename U = void>
121using enable_if_arithmetic_t = std::enable_if_t<is_arithmetic<T>::type::value, U>;
122
124template <typename WANTED, typename... TYPES>
125constexpr bool contains() {
126 return (std::is_same_v<WANTED, TYPES> || ... || false);
127}
128
130template <typename... TYPES>
131bool contains(std::type_index field) {
132 return ((field == typeid(TYPES)) || ... || false);
133}
134
136
139//TODO: check, whether this can be generalized with "list_item_with_base"
140template <
141 typename BASE,
142 typename HEAD = void, // Default argument in case the list is empty
143 typename... TAIL
144 >
146 using type = std::conditional_t<
147 std::is_base_of<BASE, HEAD>::value,
148 HEAD,
149 typename list_item_with_base_default_base<BASE, TAIL...>::type
150 >;
151};
152
153template <typename BASE, typename HEAD>
155 using type = std::conditional_t<
156 std::is_base_of<BASE, HEAD>::value,
157 HEAD,
158 BASE
159 >;
160};
161
163
166template <
167 typename BASE,
168 typename HEAD = void, // Default argument in case the list is empty
169 typename... TAIL
170>
172 using type = std::conditional_t<
173 std::is_base_of<BASE, HEAD>::value,
174 HEAD,
175 typename first_type_with_base<BASE, TAIL...>::type
176 >;
177};
178
179template <typename BASE, typename HEAD>
180struct first_type_with_base<BASE, HEAD> {
181 using type = std::conditional_t<
182 std::is_base_of<BASE, HEAD>::value,
183 HEAD,
184 void
185 >;
186};
187
188template <typename BASE, typename... TYPES>
189using first_type_with_base_t = typename first_type_with_base<BASE, TYPES...>::type;
190
192template <template<typename> typename COND, typename... TYPES>
194
195template <template<typename> typename COND, typename HEAD, typename... TAIL>
196struct index_of_first_matching<COND,HEAD,TAIL...> {
197 static constexpr unsigned value = std::conditional_t<
198 COND<HEAD>::value,
199 std::integral_constant<unsigned, 0>,
200 std::integral_constant<unsigned, 1 + index_of_first_matching<COND,TAIL...>::value>
201 >::value;
202};
203
204template <template<typename> typename COND>
206 static constexpr unsigned value = 0; // This way access into a list of this size fails (hacky)
207};
208
210template <typename... TYPES>
211struct eq {
212 template <typename T>
213 using type = std::integral_constant<bool, (std::is_same_v<TYPES,T> || ...)>;
214};
215
217template <typename... TYPES>
218struct neq {
219 template <typename T>
220 using type = std::integral_constant<bool, (!std::is_same_v<TYPES,T> && ...)>;
221};
222
224template <template <typename> class COND, typename HEAD=void, typename... TAIL>
225struct filter {
226 using type = std::conditional_t<
227 COND<HEAD>::value && !std::is_void_v<HEAD>,
228 typename filter<COND, TAIL...>::type::template push<HEAD>,
229 typename filter<COND, TAIL...>::type
230 >;
231};
232
234template <template <typename> class COND, typename TYPE>
235struct filter<COND,TYPE> {
236 using type = std::conditional_t<
237 COND<TYPE>::value && !std::is_void<TYPE>::value,
239 list<>
240 >;
241};
242
244template <template <typename> class COND, typename... TYPES>
245using filter_t = typename filter<COND,TYPES...>::type;
246
247
249template <typename HEAD=void, typename... TAIL>
250struct reverse {
251 using type = std::conditional_t<!std::is_void_v<HEAD>,
252 typename reverse<TAIL...>::type::template append<HEAD>,
253 typename reverse<TAIL...>::type
254 >;
255};
256
258template <typename TYPE>
259struct reverse<TYPE> {
260 using type = std::conditional_t<
261 !std::is_void<TYPE>::value,
263 list<>
264 >;
265};
266
268template <typename... TYPES>
269using reverse_t = typename reverse<TYPES...>::type;
270
272struct list_base { };
273
275template <typename... TYPES>
276struct list : public list_base {
277 static constexpr unsigned size = sizeof...(TYPES);
278
280 template <unsigned INDEX>
281 using get = typename std::tuple_element<INDEX, std::tuple<id<TYPES>...>>::type::type;
282
284
287 template <template<typename...> class COLLECTION>
288 using decompose_into = COLLECTION<TYPES...>;
289
290 template <template<typename> class F>
291 using map = list<F<TYPES>...>;
292
293 template <typename F>
295
296 template <typename TYPE>
297 using push = list<TYPE, TYPES...>;
298
299 template <typename... UYPES>
300 using append = list<TYPES..., UYPES...>;
301
303 template <typename... UYPES>
304 using include = typename filter_t<neq<TYPES...>::template type, UYPES...>::template decompose_into<
305 list<TYPES...>::append
306 >;
307
309 template <typename BASE>
311
313
316 template <typename BASE, typename FALLBACK>
317 using first_with_base_or_fallback = std::conditional_t<
318 std::is_void_v<first_with_base<BASE>>,
319 FALLBACK,
321 >;
322
324 template <typename TYPE>
325 static constexpr unsigned index() {
327 }
328
330 template <typename F>
331 static constexpr void for_each(F f) {
332 (f(id<TYPES>()), ...);
333 }
334
335 template <typename TYPE>
336 static constexpr bool contains() {
337 return olb::meta::contains<TYPE,TYPES...>();
338 }
339
340};
341
343template <typename LIST_A, typename LIST_B>
344using merge = typename LIST_A::template decompose_into<LIST_B::template include>;
345
347template <typename TYPES, typename F, std::size_t... INDICES>
348void list_for_each_index(F&& f, std::index_sequence<INDICES...>)
349{
350 if constexpr (std::is_invocable_v<F, decltype(id<typename TYPES::template get<0>>()), unsigned>) {
351 (f(id<typename TYPES::template get<INDICES>>(), INDICES), ...);
352 } else {
353 (f(id<typename TYPES::template get<INDICES>>()), ...);
354 }
355}
356
358template <typename TUPLE, typename F, std::size_t...INDICES>
359void tuple_for_each_index(TUPLE& tuple, F&& f, std::index_sequence<INDICES...>)
360{
361 if constexpr (std::is_invocable_v<F, decltype(std::get<0>(tuple)), std::integral_constant<std::size_t,0>>) {
362 (f(std::get<INDICES>(tuple), std::integral_constant<std::size_t,INDICES>{}), ...);
363 } else if constexpr (std::is_invocable_v<F, decltype(std::get<0>(tuple)), unsigned>) {
364 (f(std::get<INDICES>(tuple), INDICES), ...);
365 } else {
366 (f(std::get<INDICES>(tuple)), ...);
367 }
368}
369
370
372template <typename TUPLE, typename F>
373void tuple_for_each(TUPLE& tuple, F&& f)
374{
375 tuple_for_each_index(tuple, std::forward<F>(f), std::make_index_sequence<std::tuple_size<TUPLE>::value> {});
376}
377
379template <typename T, unsigned D, typename U, std::size_t... INDICES>
380std::array<T,D> make_array(U&& u, std::index_sequence<INDICES...>)
381{
382 return std::array<T,D> {(INDICES, u)...};
383}
384
386template <typename T, unsigned D, typename U>
387std::array<T,D> make_array(U&& u)
388{
389 return make_array<T,D,U>(std::forward<U>(u), std::make_index_sequence<D> {});
390}
391
393template <typename T, unsigned D, typename F, std::size_t... INDICES>
394std::array<T,D> make_array_f(F&& f, std::index_sequence<INDICES...>)
395{
396 return std::array<T,D> {f(INDICES)...};
397}
398
400template <typename T, unsigned D, typename F>
401std::array<T,D> make_array_f(F&& f)
402{
403 return make_array_f<T,D,F>(std::forward<F&&>(f), std::make_index_sequence<D> {});
404}
405
407template <auto... VALUE, typename COND>
408constexpr bool indexed_pack_contains(COND cond) {
409 std::size_t i = 0;
410 return (cond(i++, VALUE) || ...);
411}
412
413#if !defined __clang__ || __clang_major__ >= 12
414
416template <std::size_t... Is, std::size_t... Js>
417constexpr auto operator+(std::index_sequence<Is...>, std::index_sequence<Js...>)
418{
419 return std::index_sequence<Is..., Js...>();
420}
421
422#endif
423
425template <std::size_t... Is>
426constexpr auto array_from_index_sequence(std::index_sequence<Is...>)
427{
428 return std::array<std::size_t,sizeof...(Is)>{Is...};
429}
430
432template <typename PREDICATE, std::size_t... Is>
433constexpr auto filter_index_sequence(PREDICATE predicate, std::index_sequence<Is...>) {
434 return (
435 std::conditional_t<predicate(Is),
436 std::index_sequence<Is>,
437 std::index_sequence<>>()
438 + ...
439 + std::index_sequence<>()
440 );
441}
442
444template <typename TYPES, typename PREDICATE, std::size_t... Is>
445constexpr auto filter_index_sequence(PREDICATE predicate, std::index_sequence<Is...>) {
446 return (
447 std::conditional_t<predicate(id<typename TYPES::template get<Is>>()),
448 std::index_sequence<Is>,
449 std::index_sequence<>>()
450 + ...
451 + std::index_sequence<>()
452 );
453}
454
456template <typename TYPES, template<typename> class COND, std::size_t... Is>
457constexpr auto filter_index_sequence(std::index_sequence<Is...>) {
458 return (
459 std::conditional_t<COND<typename TYPES::template get<Is>>::value,
460 std::index_sequence<Is>,
461 std::index_sequence<>>()
462 + ...
463 + std::index_sequence<>()
464 );
465}
466
468template <typename TYPES, template<typename> class COND>
469constexpr auto filter_index_sequence() {
470 return filter_index_sequence<TYPES,COND>(std::make_index_sequence<TYPES::size>());
471}
472
473template <typename MAP, std::size_t... Is>
474constexpr auto map_index_sequence(MAP map, std::index_sequence<Is...>) {
475 return std::index_sequence<map(Is)...>();
476}
477
478template <std::size_t N, std::size_t I, std::size_t... Is>
479constexpr auto take_n_sequence(std::index_sequence<I,Is...>) {
480 if constexpr (N > 0) {
481 return std::index_sequence<I>() + take_n_sequence<N-1>(std::index_sequence<Is...>());
482 } else {
483 return std::index_sequence<>();
484 }
485 __builtin_unreachable();
486}
487
488template <std::size_t N, std::size_t I, std::size_t... Is>
489constexpr auto drop_n_sequence(std::index_sequence<I,Is...>) {
490 if constexpr (N > 0) {
491 return drop_n_sequence<N-1>(std::index_sequence<Is...>());
492 } else {
493 return std::index_sequence<I,Is...>();
494 }
495 __builtin_unreachable();
496}
497
498template <std::size_t N>
499constexpr auto zero_sequence() {
500 return map_index_sequence([](std::size_t) constexpr {
501 return 0;
502 }, std::make_index_sequence<N>());
503}
504
505template <std::size_t I, std::size_t O>
507 return map_index_sequence([](std::size_t Is) constexpr {
508 return (Is+I);
509 }, std::make_index_sequence<(O-I)>());
510}
511
512template <std::size_t... Is>
513constexpr bool is_zero_sequence(std::index_sequence<Is...>) {
514 return ((Is == 0) && ... && true);
515}
516
518template <typename F, std::size_t... INDICES>
519void call_n_times(F&& f, std::index_sequence<INDICES...>) {
520 (f(INDICES), ...);
521}
522
524template <unsigned N, typename F>
525void call_n_times(F&& f) {
526 return call_n_times<F>(std::forward<F&&>(f), std::make_index_sequence<N>{});
527}
528
530// index_sequence with size>1
531// - This allows filtering for specific type traits, while preserving the general order
532// - Intended to be used in the particleManger
533template <typename TYPES,typename Fa, typename Fb, std::size_t Ia, std::size_t Iaa, std::size_t... Is>
534void index_sequence_for_subsequence_L2(Fa&& fa, Fb&& fb, std::index_sequence<Ia,Iaa,Is...> seq) {
535 if constexpr (seq.size()>2) {
536 fa(id<typename TYPES::template get<Ia>>());
538 index_sequence_for_subsequence_L2<TYPES>(fa,fb,std::index_sequence<Iaa,Is...>());
539 } else {
540 fa(id<typename TYPES::template get<Ia>>());
542 fa(id<typename TYPES::template get<Iaa>>());
544 }
545}
546
548// index_sequence with size>0
549template <typename TYPES, typename Fa, typename Fb, std::size_t I, std::size_t... Is>
550void index_sequence_for_subsequence_L1(Fa&& fa, Fb&& fb, std::index_sequence<I,Is...> seq) {
551 fb(std::make_index_sequence<I>());
552 if constexpr (seq.size()>1) {
554 } else {
555 fa(id<typename TYPES::template get<I>>());
557 }
558}
559
561// index_sequence
562template <typename TYPES, typename Fa, typename Fb, std::size_t... Is>
563void index_sequence_for_subsequence(Fa&& fa, Fb&& fb, std::index_sequence<Is...> seq) {
564 if constexpr (seq.size()>0) {
566 } else {
567 fb(std::make_index_sequence<TYPES::size>());
568 }
569}
570
571template <
572 typename BASE,
573 typename HEAD = void, //Default argument in case the list is empty
574 typename ...TAIL
575>
577 auto constexpr static evaluate_type(){
578 if constexpr (!sizeof...(TAIL)) {
579 if constexpr (std::is_same<HEAD,void>::value) {
580 return id<BASE>{}; //Fallback
581 } else {
582 if constexpr(std::is_same<BASE,void>::value){
583 return id<void>{};
584 } else {
585 using HEAD_EVAL = typename BASE::template derivedField<HEAD>;
586 return id<HEAD_EVAL>{};
587 }
588 }
589 } else {
590 if constexpr(std::is_same<BASE,void>::value){
591 return id<void>{};
592 } else {
593 using HEAD_EVAL = typename BASE::template derivedField<HEAD>;
594 return id<typename derived_type_in_nested<HEAD_EVAL,TAIL...>::type>{};
595 }
596 }
597 __builtin_unreachable();
598 }
599
600 using type = typename decltype(evaluate_type())::type;
601
602 static constexpr bool contains() {
603 return !std::is_same_v<type, void>;
604 }
605};
606
607
608// *INDENT-ON*
609
610}
611
612}
613
614#endif
void tuple_for_each_index(TUPLE &tuple, F &&f, std::index_sequence< INDICES... >)
Apply F to each element of TUPLE listed in INDICES.
Definition meta.h:359
typename first_type_with_base< BASE, TYPES... >::type first_type_with_base_t
Definition meta.h:189
constexpr auto array_from_index_sequence(std::index_sequence< Is... >)
Convert index sequence into an array of its values.
Definition meta.h:426
std::string name()
Returns distinct name on GCC, Clang and ICC but may return arbitrary garbage as per the standard.
Definition meta.h:100
typename std::integral_constant< bool, std::is_base_of_v< AD, T >||std::is_base_of_v< SimdBase, T >||std::is_base_of_v< ExprBase, T >||std::is_arithmetic_v< T >||std::is_pointer_v< T >||std::is_enum_v< T > > is_arithmetic
Checks whether T can be used as a scalar arithmetic type.
Definition meta.h:109
void index_sequence_for_subsequence_L1(Fa &&fa, Fb &&fb, std::index_sequence< I, Is... > seq)
Call fa for indices in index_sequence and call fb for indices in between indices in.
Definition meta.h:550
bool is_aligned(const void *ptr)
Returns true iff address ptr is aligned w.r.t. TYPE.
Definition meta.h:69
typename LIST_A::template decompose_into< LIST_B::template include > merge
Merge elements of LIST_A and LIST_B into new list.
Definition meta.h:344
constexpr bool indexed_pack_contains(COND cond)
Returns true iff at least one VALUE satisfies COND.
Definition meta.h:408
typename filter< COND, TYPES... >::type filter_t
meta::list of TYPES meeting COND
Definition meta.h:245
plain_map< typename unzip_flattened_keys< KVs... >::type, typename unzip_flattened_values< KVs... >::type > map
Map of types.
Definition typeMap.h:88
void index_sequence_for_subsequence_L2(Fa &&fa, Fb &&fb, std::index_sequence< Ia, Iaa, Is... > seq)
Call fa for indices in index_sequence and call fb for indices in between indices in.
Definition meta.h:534
std::array< T, D > make_array_f(F &&f, std::index_sequence< INDICES... >)
Return std::array<T,D> where T is initialized using a iDim-dependent function (helper)
Definition meta.h:394
constexpr auto filter_index_sequence()
Return index sequence of Is matching COND using index_sequence of TYPES.
Definition meta.h:469
void list_for_each_index(F &&f, std::index_sequence< INDICES... >)
Apply F to each element of meta::list listed in INDICES.
Definition meta.h:348
typename reverse< TYPES... >::type reverse_t
meta::list of TYPES in reversed order
Definition meta.h:269
std::array< T, D > make_array(U &&u, std::index_sequence< INDICES... >)
Return std::array<T,D> where T is initialized with a common value (helper)
Definition meta.h:380
void index_sequence_for_subsequence(Fa &&fa, Fb &&fb, std::index_sequence< Is... > seq)
Call fa for indices in index_sequence and call fb for indices in between indices in.
Definition meta.h:563
constexpr auto make_index_sequence_in_range()
Definition meta.h:506
constexpr auto operator+(std::index_sequence< Is... >, std::index_sequence< Js... >)
Concatenate two index sequences.
Definition meta.h:417
constexpr auto take_n_sequence(std::index_sequence< I, Is... >)
Definition meta.h:479
constexpr bool is_zero_sequence(std::index_sequence< Is... >)
Definition meta.h:513
constexpr bool contains()
Returns true iff a given type list contains WANTED.
Definition meta.h:125
typename id< TYPE >::type id_t
Definition meta.h:92
std::enable_if_t< is_arithmetic< T >::type::value, U > enable_if_arithmetic_t
Definition meta.h:121
constexpr auto zero_sequence()
Definition meta.h:499
constexpr auto drop_n_sequence(std::index_sequence< I, Is... >)
Definition meta.h:489
constexpr auto map_index_sequence(MAP map, std::index_sequence< Is... >)
Definition meta.h:474
typename std::integral_constant< TYPE, VALUE >::type value
Identity type to wrap non-type template arguments.
Definition meta.h:96
void call_n_times(F &&f, std::index_sequence< INDICES... >)
Call F for each index (exlicitly unrolled loop)
Definition meta.h:519
void tuple_for_each(TUPLE &tuple, F &&f)
Apply F to each element of TUPLE.
Definition meta.h:373
Top level namespace for all of OpenLB.
Expr operator+(Expr lhs, Expr rhs)
Definition expr.cpp:171
Definition aDiff.h:43
static constexpr bool contains()
Definition meta.h:602
typename decltype(evaluate_type())::type type
Definition meta.h:600
auto static constexpr evaluate_type()
Definition meta.h:577
Evaluates to true iff T is in TYPES.
Definition meta.h:211
std::integral_constant< bool,(std::is_same_v< TYPES, T >||...)> type
Definition meta.h:213
std::conditional_t< COND< TYPE >::value &&!std::is_void< TYPE >::value, list< TYPE >, list<> > type
Definition meta.h:236
Return type list of all FIELDS meeting COND.
Definition meta.h:225
std::conditional_t< COND< HEAD >::value &&!std::is_void_v< HEAD >, typename filter< COND, TAIL... >::type::template push< HEAD >, typename filter< COND, TAIL... >::type > type
Definition meta.h:226
std::conditional_t< std::is_base_of< BASE, HEAD >::value, HEAD, void > type
Definition meta.h:181
Get first type based on BASE contained in a given type list.
Definition meta.h:171
std::conditional_t< std::is_base_of< BASE, HEAD >::value, HEAD, typename first_type_with_base< BASE, TAIL... >::type > type
Definition meta.h:172
Identity type to pass non-constructible types as value.
Definition meta.h:79
TYPE get() const
Definition meta.h:86
TYPE type
Definition meta.h:80
Helper for computing indices in type lists.
Definition meta.h:193
Base of any meta::list.
Definition meta.h:272
std::conditional_t< std::is_base_of< BASE, HEAD >::value, HEAD, BASE > type
Definition meta.h:155
Get first type based on BASE contained in a given type list.
Definition meta.h:145
std::conditional_t< std::is_base_of< BASE, HEAD >::value, HEAD, typename list_item_with_base_default_base< BASE, TAIL... >::type > type
Definition meta.h:146
Plain wrapper for list of types.
Definition meta.h:276
COLLECTION< TYPES... > decompose_into
Export TYPES into arbitrary variadic template COLLECTION.
Definition meta.h:288
typename filter_t< neq< TYPES... >::template type, UYPES... >::template decompose_into< list< TYPES... >::append > include
Merge TYPES and UYPES into new list.
Definition meta.h:304
list< TYPES..., UYPES... > append
Definition meta.h:300
first_type_with_base_t< BASE, TYPES... > first_with_base
Returns first type of TYPES that is derived from BASE.
Definition meta.h:310
static constexpr bool contains()
Definition meta.h:336
static constexpr unsigned size
Definition meta.h:277
typename std::tuple_element< INDEX, std::tuple< id< TYPES >... > >::type::type get
Returns INDEXth type of TYPES.
Definition meta.h:281
std::conditional_t< std::is_void_v< first_with_base< BASE > >, FALLBACK, first_with_base< BASE > > first_with_base_or_fallback
Returns first type of TYPES that is derived from BASE.
Definition meta.h:317
static constexpr unsigned index()
Index of first instance of TYPE in TYPES.
Definition meta.h:325
static constexpr void for_each(F f)
Calls f for each type of TYPES by-value (in reversed order!)
Definition meta.h:331
Evaluates to true iff T is not in TYPES.
Definition meta.h:218
std::integral_constant< bool,(!std::is_same_v< TYPES, T > &&...)> type
Definition meta.h:220
std::conditional_t< !std::is_void< TYPE >::value, list< TYPE >, list<> > type
Definition meta.h:260
Return type list of all FIELDS in reversed order.
Definition meta.h:250
std::conditional_t<!std::is_void_v< HEAD >, typename reverse< TAIL... >::type::template append< HEAD >, typename reverse< TAIL... >::type > type
Definition meta.h:251