FastLED
3.9.3
Loading...
Searching...
No Matches
template_magic.h
1
#pragma once
2
3
/*
4
Provides eanble_if and is_derived for compilers before C++14.
5
*/
6
7
#include <stdint.h>
8
9
#include "namespace.h"
10
11
namespace
fl {
// mandatory namespace to prevent name collision with std::enable_if.
12
13
// Define enable_if for SFINAE
14
template
<
bool
Condition,
typename
T =
void
>
15
struct
enable_if
{};
16
17
// Specialization for true condition
18
template
<
typename
T>
19
struct
enable_if
<true, T> {
20
using
type = T;
21
};
22
23
// if enable_if<Condition, T> is true, then there will be a member type
24
// called type. Otherwise it will not exist. This is (ab)used to enable
25
// constructors and other functions based on template parameters. If there
26
// is no member type, then the compiler will not fail to bind to the target
27
// function or operation.
28
template
<
bool
Condition,
typename
T =
void
>
29
using
enable_if_t =
typename
enable_if<Condition, T>::type
;
30
31
// Define is_base_of to check inheritance relationship
32
template
<
typename
Base,
typename
Derived>
33
struct
is_base_of
{
34
private
:
35
typedef
uint8_t yes;
36
typedef
uint16_t no;
37
static
yes test(Base*);
// Matches if Derived is convertible to Base*
38
static
no test(...);
// Fallback if not convertible
39
enum
{
40
kSizeDerived =
sizeof
(test(
static_cast<
Derived*
>
(
nullptr
))),
41
};
42
public
:
43
static
constexpr
bool
value = (kSizeDerived ==
sizeof
(yes));
44
};
45
46
// Define is_base_of_v for compatibility with pre-C++14
47
// Replaced variable template with a constant static member
48
template
<
typename
Base,
typename
Derived>
49
struct
is_base_of_v_helper
{
50
static
constexpr
bool
value =
is_base_of<Base, Derived>::value
;
51
};
52
53
// Define is_same trait
54
template
<
typename
T,
typename
U>
55
struct
is_same
{
56
static
constexpr
bool
value =
false
;
57
};
58
59
// Specialization for when T and U are the same type
60
template
<
typename
T>
61
struct
is_same
<T, T> {
62
static
constexpr
bool
value =
true
;
63
};
64
65
// Define is_same_v for compatibility with variable templates
66
template
<
typename
T,
typename
U>
67
struct
is_same_v_helper
{
68
static
constexpr
bool
value =
is_same<T, U>::value
;
69
};
70
71
72
// This uses template magic to maybe generate a type for the given condition. If that type
73
// doesn't exist then a type will fail to be generated, and the compiler will skip the
74
// consideration of a target function. This is useful for enabling template constructors
75
// that only become available if the class can be upcasted to the desired type.
76
//
77
// Example:
78
// This is an optional upcasting constructor for a Ref<T>. If the type U is not derived from T
79
// then the constructor will not be generated, and the compiler will skip it.
80
//
81
// template <typename U, typename = fl::is_derived<T, U>>
82
// Ref(const Ref<U>& refptr) : referent_(refptr.get());
83
template
<
typename
Base,
typename
Derived>
84
using
is_derived = enable_if_t<is_base_of<Base, Derived>::value>;
85
86
}
// namespace fl
87
88
89
// Convienence macro to define an output operator for a class to make it compatible
90
// with std::ostream. This is useful for debugging and logging. The operator will
91
// be defined as "os" and the right hand object will be named "obj".
92
//
93
// Example:
94
// FASTLED_DEFINE_OUTPUT_OPERATOR(CRGB) {
95
// os <<("CRGB(");
96
// os <<(static_cast<int>(obj.r));
97
// os <<(", ");
98
// os <<(static_cast<int>(obj.g));
99
// os <<(", ");
100
// os <<(static_cast<int>(obj.b));
101
// os <<(")");
102
// return os;
103
// }
104
//
105
// This is needed because in C++ there is two phase lookup, in which ONLY the first
106
// parameter will be considered if matched, even if the second argument is a non match.
107
//
108
// This macro get's around this issue.
109
//
110
// Consider the following templated operator definition:
111
// template<typename OutputStream>
112
// OutputStream &operator<<(OutputStream &os, const Str &str) {
113
// os << str.c_str();
114
// return os;
115
// }
116
//
117
// You would think this would only match if the left hand side is an ostream and the
118
// second parameter is "Str", but you would be wrong, because of two phase lookup
119
// this function will be considered for any type of ostream and ANY type of second
120
// parameter, even "float" or "int".
121
//
122
// This means that normally, this template will match std::stream << float
123
// then fail because of ambiguity, even though the second template is not
124
// a match. Therefore we use the enable_if which will generate a type if
125
// and only if the the second condition is a match.
126
//
127
// This essentially forces two phase lookup in one pass. Making the compiler skip
128
// the definition if the second parameter doesn't match.
129
#define FASTLED_DEFINE_OUTPUT_OPERATOR(CLASS) \
130
template <typename T, typename U> \
131
typename fl::enable_if<fl::is_same<U, CLASS>::value, T&>::type \
132
operator<<(T& os, const CLASS& obj)
fl::enable_if
Definition
template_magic.h:15
fl::is_base_of_v_helper
Definition
template_magic.h:49
fl::is_base_of
Definition
template_magic.h:33
fl::is_same_v_helper
Definition
template_magic.h:67
fl::is_same
Definition
template_magic.h:55
src
template_magic.h
Generated on Thu Nov 14 2024 00:00:34 for FastLED by
1.11.0