I need to have an interface to the driver that provides a set of send() functions only of the following types:
void send(u8 a);
void send(u8 a, u8 b);
void send(u8 a, u8 b, u8 c);
void send(u8 *a, u32 size);
I want to shorten the appearance of this interface and implement it using variable templates. As you can see, it is required, firstly, to check whether the first argument is a pointer, and if so, then handle this case separately. In other cases, you must prevent entering more than 3 arguments of type u8 (unsigned char).
I'm completely confused with the use of enable_if, SFINAE, etc.
My example:
template<typename ...Args>
void send(Args... args) {
}
void send(u8 *p, u32 size) {
}
int main() {
u8 b;
send(1); // OK
send(1, 2); // OK
send(1, 2, 3); // OK
send('1', '2', 3, 4); // NOT OK: 4 arguments were passed, I need a maximum of 3
send(&b, 10); // NOT OK: call template 'send', not specialized 'send(u8 *p, u32 size)'
}
Is this possible?
Try something like this:
void send() {} // do nothing
void send(u8 *a, u32 size) {
...
}
template<typename... Args>
void send(u8 arg, Args... args) {
static_assert(sizeof...(Args) <= 2, "No more than 3 args allowed!");
// use arg as needed, then...
send(args...); // send the rest...
}
Alternatively:
void send(u8 *a, u32 size) {
...
}
template<typename... Args>
void send(u8 arg, Args... args) {
static_assert(sizeof...(Args) <= 2, "No more than 3 args allowed!");
// use arg as needed, then...
if constexpr (sizeof...(Args) > 0) {
send(args...); // send the rest...
}
}
However, one gotcha with this approach is that something like send(1, &b, 10);
would be accepted. It would process arg=1
and then call send(&b, 10)
. If you want to avoid that, you can use additional template trickery to ensure that all of the variadic parameters are the same type, see:
Is there a way to define a variadic number of arguments of the same type?