OpenLB 1.7
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 TYPES, typename F, std::size_t... INDICES>
344void list_for_each_index(F&& f, std::index_sequence<INDICES...>)
345{
346 if constexpr (std::is_invocable_v<F, decltype(id<typename TYPES::template get<0>>()), unsigned>) {
347 (f(id<typename TYPES::template get<INDICES>>(), INDICES), ...);
348 } else {
349 (f(id<typename TYPES::template get<INDICES>>()), ...);
350 }
351}
352
354template <typename TUPLE, typename F, std::size_t...INDICES>
355void tuple_for_each_index(TUPLE& tuple, F&& f, std::index_sequence<INDICES...>)
356{
357 if constexpr (std::is_invocable_v<F, decltype(std::get<0>(tuple)), std::integral_constant<std::size_t,0>>) {
358 (f(std::get<INDICES>(tuple), std::integral_constant<std::size_t,INDICES>{}), ...);
359 } else if constexpr (std::is_invocable_v<F, decltype(std::get<0>(tuple)), unsigned>) {
360 (f(std::get<INDICES>(tuple), INDICES), ...);
361 } else {
362 (f(std::get<INDICES>(tuple)), ...);
363 }
364}
365
366
368template <typename TUPLE, typename F>
369void tuple_for_each(TUPLE& tuple, F&& f)
370{
371 tuple_for_each_index(tuple, std::forward<F>(f), std::make_index_sequence<std::tuple_size<TUPLE>::value> {});
372}
373
375template <typename T, unsigned D, typename U, std::size_t... INDICES>
376std::array<T,D> make_array(U&& u, std::index_sequence<INDICES...>)
377{
378 return std::array<T,D> {(INDICES, u)...};
379}
380
382template <typename T, unsigned D, typename U>
383std::array<T,D> make_array(U&& u)
384{
385 return make_array<T,D,U>(std::forward<U>(u), std::make_index_sequence<D> {});
386}
387
389template <typename T, unsigned D, typename F, std::size_t... INDICES>
390std::array<T,D> make_array_f(F&& f, std::index_sequence<INDICES...>)
391{
392 return std::array<T,D> {f(INDICES)...};
393}
394
396template <typename T, unsigned D, typename F>
397std::array<T,D> make_array_f(F&& f)
398{
399 return make_array_f<T,D,F>(std::forward<F&&>(f), std::make_index_sequence<D> {});
400}
401
403template <auto... VALUE, typename COND>
404constexpr bool indexed_pack_contains(COND cond) {
405 std::size_t i = 0;
406 return (cond(i++, VALUE) || ...);
407}
408
409#if !defined __clang__ || __clang_major__ >= 12
410
412template <std::size_t... Is, std::size_t... Js>
413constexpr auto operator+(std::index_sequence<Is...>, std::index_sequence<Js...>)
414{
415 return std::index_sequence<Is..., Js...>();
416}
417
418#endif
419
421template <std::size_t... Is>
422constexpr auto array_from_index_sequence(std::index_sequence<Is...>)
423{
424 return std::array<std::size_t,sizeof...(Is)>{Is...};
425}
426
428template <typename PREDICATE, std::size_t... Is>
429constexpr auto filter_index_sequence(PREDICATE predicate, std::index_sequence<Is...>) {
430 return (
431 std::conditional_t<predicate(Is),
432 std::index_sequence<Is>,
433 std::index_sequence<>>()
434 + ...
435 + std::index_sequence<>()
436 );
437}
438
440template <typename TYPES, typename PREDICATE, std::size_t... Is>
441constexpr auto filter_index_sequence(PREDICATE predicate, std::index_sequence<Is...>) {
442 return (
443 std::conditional_t<predicate(id<typename TYPES::template get<Is>>()),
444 std::index_sequence<Is>,
445 std::index_sequence<>>()
446 + ...
447 + std::index_sequence<>()
448 );
449}
450
452template <typename TYPES, template<typename> class COND, std::size_t... Is>
453constexpr auto filter_index_sequence(std::index_sequence<Is...>) {
454 return (
455 std::conditional_t<COND<typename TYPES::template get<Is>>::value,
456 std::index_sequence<Is>,
457 std::index_sequence<>>()
458 + ...
459 + std::index_sequence<>()
460 );
461}
462
464template <typename TYPES, template<typename> class COND>
465constexpr auto filter_index_sequence() {
466 return filter_index_sequence<TYPES,COND>(std::make_index_sequence<TYPES::size>());
467}
468
469template <typename MAP, std::size_t... Is>
470constexpr auto map_index_sequence(MAP map, std::index_sequence<Is...>) {
471 return std::index_sequence<map(Is)...>();
472}
473
474template <std::size_t N, std::size_t I, std::size_t... Is>
475constexpr auto take_n_sequence(std::index_sequence<I,Is...>) {
476 if constexpr (N > 0) {
477 return std::index_sequence<I>() + take_n_sequence<N-1>(std::index_sequence<Is...>());
478 } else {
479 return std::index_sequence<>();
480 }
481 __builtin_unreachable();
482}
483
484template <std::size_t N, std::size_t I, std::size_t... Is>
485constexpr auto drop_n_sequence(std::index_sequence<I,Is...>) {
486 if constexpr (N > 0) {
487 return drop_n_sequence<N-1>(std::index_sequence<Is...>());
488 } else {
489 return std::index_sequence<I,Is...>();
490 }
491 __builtin_unreachable();
492}
493
494template <std::size_t N>
495constexpr auto zero_sequence() {
496 return map_index_sequence([](std::size_t) constexpr {
497 return 0;
498 }, std::make_index_sequence<N>());
499}
500
501template <std::size_t I, std::size_t O>
503 return map_index_sequence([](std::size_t Is) constexpr {
504 return (Is+I);
505 }, std::make_index_sequence<(O-I)>());
506}
507
508template <std::size_t... Is>
509constexpr bool is_zero_sequence(std::index_sequence<Is...>) {
510 return ((Is == 0) && ... && true);
511}
512
514template <typename F, std::size_t... INDICES>
515void call_n_times(F&& f, std::index_sequence<INDICES...>) {
516 (f(INDICES), ...);
517}
518
520template <unsigned N, typename F>
521void call_n_times(F&& f) {
522 return call_n_times<F>(std::forward<F&&>(f), std::make_index_sequence<N>{});
523}
524
526// index_sequence with size>1
527// - This allows filtering for specific type traits, while preserving the general order
528// - Intended to be used in the particleManger
529template <typename TYPES,typename Fa, typename Fb, std::size_t Ia, std::size_t Iaa, std::size_t... Is>
530void index_sequence_for_subsequence_L2(Fa&& fa, Fb&& fb, std::index_sequence<Ia,Iaa,Is...> seq) {
531 if constexpr (seq.size()>2) {
532 fa(id<typename TYPES::template get<Ia>>());
533 fb(make_index_sequence_in_range<Ia+1,Iaa>());
534 index_sequence_for_subsequence_L2<TYPES>(fa,fb,std::index_sequence<Iaa,Is...>());
535 } else {
536 fa(id<typename TYPES::template get<Ia>>());
537 fb(make_index_sequence_in_range<Ia+1,Iaa>());
538 fa(id<typename TYPES::template get<Iaa>>());
539 fb(make_index_sequence_in_range<Iaa+1,TYPES::size>());
540 }
541}
542
544// index_sequence with size>0
545template <typename TYPES, typename Fa, typename Fb, std::size_t I, std::size_t... Is>
546void index_sequence_for_subsequence_L1(Fa&& fa, Fb&& fb, std::index_sequence<I,Is...> seq) {
547 fb(std::make_index_sequence<I>());
548 if constexpr (seq.size()>1) {
549 index_sequence_for_subsequence_L2<TYPES>(fa, fb, seq );
550 } else {
551 fa(id<typename TYPES::template get<I>>());
552 fb(make_index_sequence_in_range<I+1,TYPES::size>());
553 }
554}
555
557// index_sequence
558template <typename TYPES, typename Fa, typename Fb, std::size_t... Is>
559void index_sequence_for_subsequence(Fa&& fa, Fb&& fb, std::index_sequence<Is...> seq) {
560 if constexpr (seq.size()>0) {
561 index_sequence_for_subsequence_L1<TYPES>(fa, fb, seq );
562 } else {
563 fb(std::make_index_sequence<TYPES::size>());
564 }
565}
566
567template <
568 typename BASE,
569 typename HEAD = void, //Default argument in case the list is empty
570 typename ...TAIL
571>
573 auto constexpr static evaluate_type(){
574 if constexpr (!sizeof...(TAIL)) {
575 if constexpr (std::is_same<HEAD,void>::value) {
576 return id<BASE>{}; //Fallback
577 } else {
578 if constexpr(std::is_same<BASE,void>::value){
579 return id<void>{};
580 } else {
581 using HEAD_EVAL = typename BASE::template derivedField<HEAD>;
582 return id<HEAD_EVAL>{};
583 }
584 }
585 } else {
586 if constexpr(std::is_same<BASE,void>::value){
587 return id<void>{};
588 } else {
589 using HEAD_EVAL = typename BASE::template derivedField<HEAD>;
590 return id<typename derived_type_in_nested<HEAD_EVAL,TAIL...>::type>{};
591 }
592 }
593 __builtin_unreachable();
594 }
595
596 using type = typename decltype(evaluate_type())::type;
597
598 static constexpr bool contains() {
599 return !std::is_same_v<type, void>;
600 }
601};
602
603
604// *INDENT-ON*
605
606}
607
608}
609
610#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:355
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:422
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:546
bool is_aligned(const void *ptr)
Returns true iff address ptr is aligned w.r.t. TYPE.
Definition meta.h:69
constexpr bool indexed_pack_contains(COND cond)
Returns true iff at least one VALUE satisfies COND.
Definition meta.h:404
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:530
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:390
constexpr auto filter_index_sequence()
Return index sequence of Is matching COND using index_sequence of TYPES.
Definition meta.h:465
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:344
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:376
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:559
constexpr auto make_index_sequence_in_range()
Definition meta.h:502
constexpr auto operator+(std::index_sequence< Is... >, std::index_sequence< Js... >)
Concatenate two index sequences.
Definition meta.h:413
constexpr auto take_n_sequence(std::index_sequence< I, Is... >)
Definition meta.h:475
constexpr bool is_zero_sequence(std::index_sequence< Is... >)
Definition meta.h:509
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:495
constexpr auto drop_n_sequence(std::index_sequence< I, Is... >)
Definition meta.h:485
constexpr auto map_index_sequence(MAP map, std::index_sequence< Is... >)
Definition meta.h:470
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:515
void tuple_for_each(TUPLE &tuple, F &&f)
Apply F to each element of TUPLE.
Definition meta.h:369
Top level namespace for all of OpenLB.
Definition aDiff.h:43
static constexpr bool contains()
Definition meta.h:598
typename decltype(evaluate_type())::type type
Definition meta.h:596
auto static constexpr evaluate_type()
Definition meta.h:573
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