metaprogrammingdefs.h
9.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/* ****************************************************************************
* Copyright 2019 Open Systems Development BV *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
* ***************************************************************************/
#ifndef OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H
#define OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H
#include <cstddef> // for std::size_t
#include <sstream>
#include <string>
#include "utils.h"
/**
* @brief Create a type trait that checks for the existence of a member in a struct.
* @param memberName The member name
*
* A call such as OSDEV_COMPONENTS_HASMEMBER_TRAIT(onSuccess) leads to a type trait has_onSuccess.
*/
#define OSDEV_COMPONENTS_HASMEMBER_TRAIT(memberName) \
template <typename T, typename = void> \
struct has_##memberName : public std::false_type \
{ \
}; \
\
template <typename T> \
struct has_##memberName<T, osdev::components::mqtt::void_t<decltype(std::declval<T>().memberName)>> : public std::true_type \
{ \
};
/**
* @brief Create a type trait that checks for the existence of a member method with no parameters.
* @param methodName The method name
* @param postfix An extra postfix that is added to the type trait struct.
* This makes it possible create type traits that check for
* overloaded methods.
*
* A call such as OSDEV_COMPONENTS_HASMETHOD_TRAIT(capacity,1) leads to a type trait has_capacity1.
*/
#define OSDEV_COMPONENTS_HASMETHOD_TRAIT(methodName, postfix) \
template <typename T, typename = void> \
struct has_##methodName##postfix : public std::false_type \
{ \
}; \
\
template <typename T> \
struct has_##methodName##postfix<T, osdev::components::mqtt::void_t<decltype(std::declval<T>().methodName())>> : public std::true_type \
{ \
};
/**
* @brief Create a type trait that checks for the existence of a member method with 1 or more parameters.
* @param methodName The method name
* @param postfix An extra postfix that is added to the type trait struct.
* This makes it possible create type traits that check for
* overloaded methods.
* @param ... Variable number of arguments. These can be values, but also declval constructs such as std::declval<MyClass>().
*
* A call such as OSDEV_COMPONENTS_HASMETHODWP_TRAIT(capacity,,"string") leads to a type trait has_capacity that
* checks for the existence of a method capacity that accepts a const char pointer.
*/
#define OSDEV_COMPONENTS_HASMETHODWP_TRAIT(methodName, postfix, ...) \
template <typename T, typename = void> \
struct has_##methodName##postfix : public std::false_type \
{ \
}; \
\
template <typename T> \
struct has_##methodName##postfix<T, osdev::components::mqtt::void_t<decltype(std::declval<T>().methodName(__VA_ARGS__))>> : public std::true_type \
{ \
};
namespace osdev {
namespace components {
namespace mqtt {
/**
* @brief Used to detect ill formed types in a SFINAE context.
* If the parameter pack Ts contains an invalid type, struct make_void cannot be expanded.
*/
template <typename... Ts>
struct make_void
{
using type = void;
};
/**
* @brief Introduced in c++17 (but will also work in c++11)
*/
template <typename... Ts>
using void_t = typename make_void<Ts...>::type;
/// @brief Build an index list that can be used to traverse another list (f.i. a char array).
/// Recursive definition.
/// Start with an empty indices list. Build the indices list recursively.
/// upper-1, indices... becomes the indices... in the next recursive call.
template <std::size_t lower, std::size_t upper,
template <std::size_t...> class meta_functor, std::size_t... Is>
struct apply_bounded_range
{
typedef typename apply_bounded_range<lower, upper - 1, meta_functor, upper - 1, Is...>::result result;
};
/// @brief Terminator of apply_bounded_range.
/// Terminates when the upper bound (which runs) is equal to the lower bound.
template <std::size_t lower, template <std::size_t...> class meta_functor, std::size_t... Is>
struct apply_bounded_range<lower, lower, meta_functor, Is...>
{
typedef typename meta_functor<Is...>::result result;
};
/**
* @brief Helper method to perform static_assert on the expected count of a parameter pack.
*/
template <std::size_t expectedCount, typename... Args>
void static_assert_count()
{
constexpr std::size_t actualCount = sizeof...(Args);
static_assert(expectedCount == actualCount, "Unexpected parameter count.");
}
/**
* @brief Helper method to convert a type to std::string.
* @param d_first The output iterator to write the converted string to.
* @param arg The argument to convert to std::string.
*/
template <typename OutputIt, typename T>
int apply_to_string_one(OutputIt d_first, const T& arg)
{
std::ostringstream ss;
ss << arg;
*d_first++ = ss.str();
return 0;
}
/**
* @brief Converts all parameters to std::string.
* @param d_first The output iterator to write the converted strings to.
* @param args The arguments to convert to std::string.
*/
template <typename OutputIt, typename... Args>
void apply_to_string(OutputIt d_first, Args&&... args)
{
// d_first is not used when args parameter pack is empty.
apply_unused_parameters(d_first);
// We need to use the expand_type trick in order to be able to use an initializer list
// so that we can call the method for every variadic argument
using expand_type = int[];
// Array must be initialized with values. Add a single value so that the array can be initialized when the parameter pack is empty.
expand_type et{ 0, apply_to_string_one(d_first, std::forward<Args>(args))... };
apply_unused_parameters(et);
}
/**
* @brief Helper that removes const, volatile and reference from a type.
* @note Defined in std C++20.
*/
template <typename T>
struct remove_cvref
{
using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};
} // End namespace mqtt
} // End namespace components
} // End namespace osdev
#endif // OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H