FastLED 3.9.15
Loading...
Searching...
No Matches
type_traits.h
Go to the documentation of this file.
1#pragma once
2
3/*
4Provides eanble_if and is_derived for compilers before C++14.
5*/
6
7#include <string.h> // for memcpy
8
9#include "fl/stdint.h"
10
11#include "fl/namespace.h"
12#include "fl/move.h"
13#include "fl/int.h"
14
15namespace fl { // mandatory namespace to prevent name collision with
16 // std::enable_if.
17
18// Define integral_constant as base for true_type and false_type
19template <typename T, T v>
21 static constexpr T value = v;
22 using value_type = T;
24 constexpr operator value_type() const noexcept { return value; }
25 constexpr value_type operator()() const noexcept { return value; }
26};
27
28// Define true_type and false_type
31
32// Define add_rvalue_reference trait (remove_reference is already defined in move.h)
33template <typename T> struct add_rvalue_reference {
34 using type = T&&;
35};
36
37template <typename T> struct add_rvalue_reference<T&> {
38 using type = T&;
39};
40
41// Define declval for use in SFINAE expressions
42template <typename T>
44
45// Define enable_if for SFINAE
46template <bool Condition, typename T = void> struct enable_if {};
47
48// Specialization for true condition
49template <typename T> struct enable_if<true, T> {
50 using type = T;
51};
52
53// if enable_if<Condition, T> is true, then there will be a member type
54// called type. Otherwise it will not exist. This is (ab)used to enable
55// constructors and other functions based on template parameters. If there
56// is no member type, then the compiler will not fail to bind to the target
57// function or operation.
58template <bool Condition, typename T = void>
60
61// Define is_base_of to check inheritance relationship
62template <typename Base, typename Derived> struct is_base_of {
63 private:
64 typedef u8 yes;
65 typedef u16 no;
66 static yes test(Base *); // Matches if Derived is convertible to Base*
67 static no test(...); // Fallback if not convertible
68 enum {
69 kSizeDerived = sizeof(test(static_cast<Derived *>(nullptr))),
70 };
71
72 public:
73 static constexpr bool value = (kSizeDerived == sizeof(yes));
74};
75
76// Define is_base_of_v for compatibility with pre-C++14
77// Replaced variable template with a constant static member
78template <typename Base, typename Derived> struct is_base_of_v_helper {
79 static constexpr bool value = is_base_of<Base, Derived>::value;
80};
81
82// Define is_same trait
83template <typename T, typename U> struct is_same {
84 static constexpr bool value = false;
85};
86
87// Specialization for when T and U are the same type
88template <typename T> struct is_same<T, T> {
89 static constexpr bool value = true;
90};
91
92// Define is_same_v for compatibility with variable templates
93template <typename T, typename U> struct is_same_v_helper {
94 static constexpr bool value = is_same<T, U>::value;
95};
96
97
98// Define conditional trait
99template <bool B, typename T, typename F> struct conditional {
100 using type = T;
101};
102
103template <typename T, typename F> struct conditional<false, T, F> {
104 using type = F;
105};
106
107template <bool B, typename T, typename F>
109
110// Define is_array trait
111template <typename T> struct is_array {
112 static constexpr bool value = false;
113};
114
115template <typename T> struct is_array<T[]> {
116 static constexpr bool value = true;
117};
118
119template <typename T, fl::size N> struct is_array<T[N]> {
120 static constexpr bool value = true;
121};
122
123// Define remove_extent trait
124template <typename T> struct remove_extent {
125 using type = T;
126};
127
128template <typename T> struct remove_extent<T[]> {
129 using type = T;
130};
131
132template <typename T, fl::size N> struct remove_extent<T[N]> {
133 using type = T;
134};
135
136// Define is_function trait
137template <typename T> struct is_function {
138 static constexpr bool value = false;
139};
140
141template <typename Ret, typename... Args> struct is_function<Ret(Args...)> {
142 static constexpr bool value = true;
143};
144
145template <typename Ret, typename... Args>
146struct is_function<Ret(Args...) const> {
147 static constexpr bool value = true;
148};
149
150template <typename Ret, typename... Args>
151struct is_function<Ret(Args...) volatile> {
152 static constexpr bool value = true;
153};
154
155template <typename Ret, typename... Args>
156struct is_function<Ret(Args...) const volatile> {
157 static constexpr bool value = true;
158};
159
160// Define add_pointer trait
161template <typename T> struct add_pointer {
162 using type = T *;
163};
164
165template <typename T> struct add_pointer<T &> {
166 using type = T *;
167};
168
169template <typename T> struct add_pointer<T &&> {
170 using type = T *;
171};
172
173template <typename T> using add_pointer_t = typename add_pointer<T>::type;
174
175// Define remove_const trait
176template <typename T> struct remove_const {
177 using type = T;
178};
179
180template <typename T> struct remove_const<const T> {
181 using type = T;
182};
183
184// Define is_const trait
185template <typename T> struct is_const {
186 static constexpr bool value = false;
187};
188
189template <typename T> struct is_const<const T> {
190 static constexpr bool value = true;
191};
192
193// Define is_lvalue_reference trait
194template <typename T> struct is_lvalue_reference {
195 static constexpr bool value = false;
196};
197
198template <typename T> struct is_lvalue_reference<T &> {
199 static constexpr bool value = true;
200};
201
202// Define is_void trait
203template <typename T> struct is_void {
204 static constexpr bool value = false;
205};
206
207template <> struct is_void<void> {
208 static constexpr bool value = true;
209};
210
211// Implementation of forward
212template <typename T>
213constexpr T &&forward(typename remove_reference<T>::type &t) noexcept {
214 return static_cast<T &&>(t);
215}
216
217// Overload for rvalue references
218template <typename T>
219constexpr T &&forward(typename remove_reference<T>::type &&t) noexcept {
220 static_assert(!is_lvalue_reference<T>::value,
221 "Cannot forward an rvalue as an lvalue");
222 return static_cast<T &&>(t);
223}
224
225// Define remove_cv trait
226template <typename T> struct remove_cv {
227 using type = T;
228};
229
230template <typename T> struct remove_cv<const T> {
231 using type = T;
232};
233
234template <typename T> struct remove_cv<volatile T> {
235 using type = T;
236};
237
238template <typename T> struct remove_cv<const volatile T> {
239 using type = T;
240};
241
242template <typename T> using remove_cv_t = typename remove_cv<T>::type;
243
244// Define decay trait
245template <typename T> struct decay {
246 private:
247 using U = typename remove_reference<T>::type;
248
249 public:
250 using type = typename conditional<
253 typename add_pointer<U>::type,
255};
256
257template <typename T> using decay_t = typename decay<T>::type;
258
259// Define is_pod trait (basic implementation)
260template <typename T> struct is_pod {
261 static constexpr bool value = false; // Default to false for safety
262};
263
264// Specializations for fundamental types
265template <> struct is_pod<bool> {
266 static constexpr bool value = true;
267};
268template <> struct is_pod<char> {
269 static constexpr bool value = true;
270};
271template <> struct is_pod<signed char> {
272 static constexpr bool value = true;
273};
274template <> struct is_pod<unsigned char> {
275 static constexpr bool value = true;
276};
277template <> struct is_pod<short> {
278 static constexpr bool value = true;
279};
280template <> struct is_pod<unsigned short> {
281 static constexpr bool value = true;
282};
283template <> struct is_pod<int> {
284 static constexpr bool value = true;
285};
286template <> struct is_pod<unsigned int> {
287 static constexpr bool value = true;
288};
289template <> struct is_pod<long> {
290 static constexpr bool value = true;
291};
292template <> struct is_pod<unsigned long> {
293 static constexpr bool value = true;
294};
295template <> struct is_pod<long long> {
296 static constexpr bool value = true;
297};
298template <> struct is_pod<unsigned long long> {
299 static constexpr bool value = true;
300};
301template <> struct is_pod<float> {
302 static constexpr bool value = true;
303};
304template <> struct is_pod<double> {
305 static constexpr bool value = true;
306};
307template <> struct is_pod<long double> {
308 static constexpr bool value = true;
309};
310
311// Helper struct for is_pod_v (similar to other _v helpers)
312template <typename T> struct is_pod_v_helper {
313 static constexpr bool value = is_pod<T>::value;
314};
315
316//----------------------------------------------------------------------------
317// trait to detect pointer‑to‑member‑function
318// must come before Function so SFINAE sees it
319//----------------------------------------------------------------------------
320template <typename T> struct is_member_function_pointer;
321template <typename C, typename Ret, typename... A>
322struct is_member_function_pointer<Ret (C::*)(A...)>;
323template <typename C, typename Ret, typename... A>
324struct is_member_function_pointer<Ret (C::*)(A...) const>;
325
326template <typename T> struct is_member_function_pointer {
327 static constexpr bool value = false;
328};
329
330template <typename C, typename Ret, typename... A>
331struct is_member_function_pointer<Ret (C::*)(A...)> {
332 static constexpr bool value = true;
333};
334
335template <typename C, typename Ret, typename... A>
336struct is_member_function_pointer<Ret (C::*)(A...) const> {
337 static constexpr bool value = true;
338};
339
340//-------------------------------------------------------------------------------
341// is_integral trait (built-in integer types only)
342//-------------------------------------------------------------------------------
343template <typename T> struct is_integral {
344 static constexpr bool value = false;
345};
346template <> struct is_integral<bool> {
347 static constexpr bool value = true;
348};
349template <> struct is_integral<char> {
350 static constexpr bool value = true;
351};
352template <> struct is_integral<signed char> {
353 static constexpr bool value = true;
354};
355template <> struct is_integral<unsigned char> {
356 static constexpr bool value = true;
357};
358template <> struct is_integral<short> {
359 static constexpr bool value = true;
360};
361template <> struct is_integral<unsigned short> {
362 static constexpr bool value = true;
363};
364template <> struct is_integral<int> {
365 static constexpr bool value = true;
366};
367template <> struct is_integral<unsigned int> {
368 static constexpr bool value = true;
369};
370template <> struct is_integral<long> {
371 static constexpr bool value = true;
372};
373template <> struct is_integral<unsigned long> {
374 static constexpr bool value = true;
375};
376template <> struct is_integral<long long> {
377 static constexpr bool value = true;
378};
379template <> struct is_integral<unsigned long long> {
380 static constexpr bool value = true;
381};
382
383template <typename T> struct is_integral<const T> {
384 static constexpr bool value = is_integral<T>::value;
385};
386
387template <typename T> struct is_integral<volatile T> {
388 static constexpr bool value = is_integral<T>::value;
389};
390
391template <typename T> struct is_integral<T &> {
392 static constexpr bool value = is_integral<T>::value;
393};
394
395//-------------------------------------------------------------------------------
396// is_floating_point trait
397//-------------------------------------------------------------------------------
398template <typename T> struct is_floating_point {
399 static constexpr bool value = false;
400};
401template <> struct is_floating_point<float> {
402 static constexpr bool value = true;
403};
404template <> struct is_floating_point<double> {
405 static constexpr bool value = true;
406};
407template <> struct is_floating_point<long double> {
408 static constexpr bool value = true;
409};
410
411template <typename T> struct is_floating_point<const T> {
412 static constexpr bool value = is_floating_point<T>::value;
413};
414
415template <typename T> struct is_floating_point<volatile T> {
416 static constexpr bool value = is_floating_point<T>::value;
417};
418
419template <typename T> struct is_floating_point<T &> {
420 static constexpr bool value = is_floating_point<T>::value;
421};
422
423//-------------------------------------------------------------------------------
424// is_signed trait
425//-------------------------------------------------------------------------------
426template <typename T> struct is_signed {
427 static constexpr bool value = false;
428};
429template <> struct is_signed<signed char> {
430 static constexpr bool value = true;
431};
432template <> struct is_signed<short> {
433 static constexpr bool value = true;
434};
435template <> struct is_signed<int> {
436 static constexpr bool value = true;
437};
438template <> struct is_signed<long> {
439 static constexpr bool value = true;
440};
441template <> struct is_signed<long long> {
442 static constexpr bool value = true;
443};
444template <> struct is_signed<float> {
445 static constexpr bool value = true;
446};
447template <> struct is_signed<double> {
448 static constexpr bool value = true;
449};
450template <> struct is_signed<long double> {
451 static constexpr bool value = true;
452};
453// Note: sized integer types (i8, i16, i32, int64_t) are typedefs
454// for the basic types above, so they automatically inherit these specializations
455
456//-------------------------------------------------------------------------------
457// Type size ranking for promotion rules
458//-------------------------------------------------------------------------------
459template <typename T> struct type_rank {
460 static constexpr int value = 0;
461};
462template <> struct type_rank<bool> {
463 static constexpr int value = 1;
464};
465template <> struct type_rank<signed char> {
466 static constexpr int value = 2;
467};
468template <> struct type_rank<unsigned char> {
469 static constexpr int value = 2;
470};
471template <> struct type_rank<char> {
472 static constexpr int value = 2;
473};
474template <> struct type_rank<short> {
475 static constexpr int value = 3;
476};
477template <> struct type_rank<unsigned short> {
478 static constexpr int value = 3;
479};
480template <> struct type_rank<int> {
481 static constexpr int value = 4;
482};
483template <> struct type_rank<unsigned int> {
484 static constexpr int value = 4;
485};
486template <> struct type_rank<long> {
487 static constexpr int value = 5;
488};
489template <> struct type_rank<unsigned long> {
490 static constexpr int value = 5;
491};
492template <> struct type_rank<long long> {
493 static constexpr int value = 6;
494};
495template <> struct type_rank<unsigned long long> {
496 static constexpr int value = 6;
497};
498template <> struct type_rank<float> {
499 static constexpr int value = 10;
500};
501template <> struct type_rank<double> {
502 static constexpr int value = 11;
503};
504template <> struct type_rank<long double> {
505 static constexpr int value = 12;
506};
507// Note: sized integer types (i8, i16, i32, int64_t) are typedefs
508// for the basic types above, so they automatically inherit these specializations
509
510//-------------------------------------------------------------------------------
511// Helper templates for integer type promotion logic
512//-------------------------------------------------------------------------------
513
514// Helper: Choose type based on size (larger wins)
515template <typename T, typename U>
517 using type = typename conditional<
518 (sizeof(T) > sizeof(U)), T,
519 typename conditional<
520 (sizeof(U) > sizeof(T)), U,
521 void // same size - handled elsewhere
522 >::type
523 >::type;
524};
525
526// Helper: Choose type based on type rank when same size (higher rank wins)
527template <typename T, typename U>
529 using type = typename conditional<
531 typename conditional<
533 void // same rank - handled elsewhere
534 >::type
535 >::type;
536};
537
538// Helper: Choose type based on signedness when same size and rank (signed wins)
539template <typename T, typename U>
541 static constexpr bool t_signed = is_signed<T>::value;
542 static constexpr bool u_signed = is_signed<U>::value;
543 static constexpr bool mixed_signedness = (t_signed != u_signed);
544
545 using type = typename conditional<
547 typename conditional<
549 T // same signedness - just pick first
550 >::type
551 >::type;
552};
553
554// Helper: Main integer promotion logic dispatcher
555template <typename T, typename U>
557 static constexpr bool same_size = (sizeof(T) == sizeof(U));
559
563
564 using type = typename conditional<
566 typename conditional<
568 by_signedness_result // same size and rank
569 >::type
570 >::type;
571};
572
573//-------------------------------------------------------------------------------
574// Common type trait for type promotion - now much cleaner!
575//-------------------------------------------------------------------------------
576
577// Primary template - fallback
578template <typename T, typename U, typename = void> struct common_type_impl {
579 using type = T;
580};
581
582// Same type specialization - handles all cases where T == U
583template <typename T> struct common_type_impl<T, T> {
584 using type = T;
585};
586
587// Float/double specializations - only exist when T is numeric but not the same type, otherwise compilation fails
588template <typename T>
589struct common_type_impl<T, float, typename enable_if<(is_integral<T>::value || is_floating_point<T>::value) && !is_same<T, float>::value>::type> {
590 using type = float;
591};
592
593template <typename T>
594struct common_type_impl<T, double, typename enable_if<(is_integral<T>::value || is_floating_point<T>::value) && !is_same<T, double>::value>::type> {
595 using type = double;
596};
597
598// Symmetric specializations - when first type is float/double and second is numeric but not the same type
599template <typename T>
600struct common_type_impl<float, T, typename enable_if<(is_integral<T>::value || is_floating_point<T>::value) && !is_same<T, float>::value>::type> {
601 using type = float;
602};
603
604template <typename T>
605struct common_type_impl<double, T, typename enable_if<(is_integral<T>::value || is_floating_point<T>::value) && !is_same<T, double>::value>::type> {
606 using type = double;
607};
608
609// Explicitly forbid i8 and u8 combinations
610// No type member = clear compilation error when accessed
611template <>
612struct common_type_impl<i8, u8, void> {
613 // Intentionally no 'type' member - will cause error:
614 // "no type named 'type' in 'struct fl::common_type_impl<signed char, unsigned char, void>'"
615};
616
617template <>
618struct common_type_impl<u8, i8, void> {
619 // Intentionally no 'type' member - will cause error:
620 // "no type named 'type' in 'struct fl::common_type_impl<unsigned char, signed char, void>'"
621};
622
623// Generic integer promotion logic - now much cleaner!
624template <typename T, typename U>
625struct common_type_impl<T, U, typename enable_if<
626 is_integral<T>::value && is_integral<U>::value &&
627 !is_same<T, U>::value &&
628 !((is_same<T, i8>::value && is_same<U, u8>::value) ||
629 (is_same<T, u8>::value && is_same<U, i8>::value))
630>::type> {
632};
633
634// Mixed floating point sizes - larger wins
635template <> struct common_type_impl<float, double> { using type = double; };
636template <> struct common_type_impl<double, float> { using type = double; };
637template <> struct common_type_impl<float, long double> { using type = long double; };
638template <> struct common_type_impl<long double, float> { using type = long double; };
639template <> struct common_type_impl<double, long double> { using type = long double; };
640template <> struct common_type_impl<long double, double> { using type = long double; };
641
642template <typename T, typename U> struct common_type {
644};
645
646template <typename T, typename U>
648
649// This uses template magic to maybe generate a type for the given condition. If
650// that type doesn't exist then a type will fail to be generated, and the
651// compiler will skip the consideration of a target function. This is useful for
652// enabling template constructors that only become available if the class can be
653// upcasted to the desired type.
654//
655// Example:
656// This is an optional upcasting constructor for a Ref<T>. If the type U is not
657// derived from T then the constructor will not be generated, and the compiler
658// will skip it.
659//
660// template <typename U, typename = fl::is_derived<T, U>>
661// Ref(const Ref<U>& refptr) : referent_(refptr.get());
662template <typename Base, typename Derived>
664
665//-----------------------------------------------------------------------------
666// detect whether T has a member void swap(T&)
667//-----------------------------------------------------------------------------
668template <typename T> struct has_member_swap {
669 private:
670 // must be 1 byte vs. >1 byte for sizeof test
671 typedef u8 yes;
672 typedef u16 no;
673
674 // helper<U, &U::swap> is only well-formed if U::swap(T&) exists with that
675 // signature
676 template <typename U, void (U::*M)(U &)> struct helper {};
677
678 // picks this overload if helper<U, &U::swap> is valid
679 template <typename U> static yes test(helper<U, &U::swap> *);
680
681 // fallback otherwise
682 template <typename> static no test(...);
683
684 public:
685 static constexpr bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
686};
687
688// primary template: dispatch on has_member_swap<T>::value
689template <typename T, bool = has_member_swap<T>::value> struct swap_impl;
690
691// POD case - now using move semantics for better performance
692template <typename T> struct swap_impl<T, false> {
693 static void apply(T &a, T &b) {
694 T tmp = fl::move(a);
695 a = fl::move(b);
696 b = fl::move(tmp);
697 }
698};
699
700// non‑POD case (requires T implements swap)
701template <typename T> struct swap_impl<T, true> {
702 static void apply(T &a, T &b) { a.swap(b); }
703};
704
705// single entry‑point
706template <typename T> void swap(T &a, T &b) {
707 // if T is a POD, use use a simple data copy swap.
708 // if T is not a POD, use the T::Swap method.
710}
711
712template <typename T> void swap_by_copy(T &a, T &b) {
713 // Force copy semantics (for cases where move might not be safe)
714 T tmp = a;
715 a = b;
716 b = tmp;
717}
718
719// Container type checks.
720template <typename T, typename... Types> struct contains_type;
721
722template <typename T> struct contains_type<T> {
723 static constexpr bool value = false;
724};
725
726template <typename T, typename U, typename... Rest>
727struct contains_type<T, U, Rest...> {
728 static constexpr bool value =
730};
731
732// Helper to get maximum size of types
733template <typename... Types> struct max_size;
734
735template <> struct max_size<> {
736 static constexpr fl::size value = 0;
737};
738
739template <typename T, typename... Rest> struct max_size<T, Rest...> {
740 static constexpr fl::size value = (sizeof(T) > max_size<Rest...>::value)
741 ? sizeof(T)
742 : max_size<Rest...>::value;
743};
744
745// Helper to get maximum alignment of types
746template <typename... Types> struct max_align;
747
748template <> struct max_align<> {
749 static constexpr fl::size value = 1;
750};
751
752template <typename T, typename... Rest> struct max_align<T, Rest...> {
753 static constexpr fl::size value = (alignof(T) > max_align<Rest...>::value)
754 ? alignof(T)
755 : max_align<Rest...>::value;
756};
757
758// alignment_of trait
759template <typename T>
761 static constexpr fl::size value = alignof(T);
762};
763
764
765
766} // namespace fl
767
768// For comparison operators that return bool against pod data. The class obj
769// will need to supply the comparison operator for the pod type. This example
770// will show how to define a comparison operator for a class that can be
771// compared against a pod type.
772// Example:
773// FASTLED_DEFINE_POD_COMPARISON_OPERATOR(Myclass, >=) will allow MyClass to
774// be compared MyClass obj; return obj >= 0;
775#define FASTLED_DEFINE_POD_COMPARISON_OPERATOR(CLASS, OP) \
776 template <typename T, typename U> \
777 typename fl::enable_if< \
778 fl::is_same<U, CLASS>::value && fl::is_pod<T>::value, bool>::type \
779 operator OP(const T &pod, const CLASS &obj) { \
780 return pod OP obj; \
781 } \
782 template <typename T> \
783 typename fl::enable_if<fl::is_pod<T>::value, bool>::type operator OP( \
784 const CLASS &obj, const T &pod) { \
785 return obj OP pod; \
786 }
static uint32_t t
Definition Luminova.h:54
Implements the FastLED namespace macros.
constexpr remove_reference< T >::type && move(T &&t) noexcept
Definition move.h:27
unsigned char u8
Definition int.h:17
typename common_type< T, U >::type common_type_t
typename conditional< B, T, F >::type conditional_t
void swap(array< T, N > &lhs, array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Definition array.h:156
typename remove_cv< T >::type remove_cv_t
integral_constant< bool, false > false_type
Definition type_traits.h:30
typename decay< T >::type decay_t
enable_if_t< is_base_of< Base, Derived >::value > is_derived
add_rvalue_reference< T >::type declval() noexcept
void swap_by_copy(T &a, T &b)
typename add_pointer< T >::type add_pointer_t
signed char i8
Definition int.h:16
typename enable_if< Condition, T >::type enable_if_t
Definition type_traits.h:59
integral_constant< bool, true > true_type
Definition type_traits.h:29
constexpr T && forward(typename remove_reference< T >::type &t) noexcept
IMPORTANT!
Definition crgb.h:20
typename conditional<(sizeof(T) > sizeof(U)), T, typename conditional<(sizeof(U) > sizeof(T)), U, void >::type >::type type
typename common_type_impl< T, U >::type type
typename conditional<(type_rank< T >::value > type_rank< U >::value), T, typename conditional<(type_rank< U >::value > type_rank< T >::value), U, void >::type >::type type
static constexpr fl::size value
static constexpr bool t_signed
static constexpr bool u_signed
typename conditional< mixed_signedness &&t_signed, T, typename conditional< mixed_signedness &&u_signed, U, T >::type >::type type
static constexpr bool mixed_signedness
static constexpr bool value
typename remove_reference< T >::type U
typename conditional< is_array< U >::value, typename remove_extent< U >::type *, typename conditional< is_function< U >::value, typename add_pointer< U >::type, typename remove_cv< U >::type >::type >::type type
static no test(...)
static yes test(helper< U, &U::swap > *)
static constexpr bool value
typename conditional< !same_size, by_size_result, typename conditional< same_size &&!same_rank, by_rank_result, by_signedness_result >::type >::type type
typename choose_by_signedness< T, U >::type by_signedness_result
typename choose_by_size< T, U >::type by_size_result
static constexpr bool same_rank
typename choose_by_rank< T, U >::type by_rank_result
static constexpr bool same_size
integral_constant type
Definition type_traits.h:23
constexpr value_type operator()() const noexcept
Definition type_traits.h:25
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
Definition type_traits.h:79
static no test(...)
static constexpr bool value
Definition type_traits.h:73
static yes test(Base *)
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
Definition type_traits.h:89
static constexpr bool value
Definition type_traits.h:94
static constexpr bool value
Definition type_traits.h:84
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr bool value
static constexpr fl::size value
static constexpr fl::size value
static constexpr fl::size value
static constexpr fl::size value
static void apply(T &a, T &b)
static void apply(T &a, T &b)
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value
static constexpr int value