I have the following function which can take N arguments of different types, and forwards them to N functions templated on each individual type, in this manner (example with two arguments):
template <typename T1, typename T2>
bool func(int& counter, T1 x1, T2 x2) {
switch (counter) {
case 0:
if (func2<T1>(x1)) {
counter++;
return true;
} else {
return false;
}
case 1:
if (func2<T2>(x2)) {
counter++;
return true;
} else {
return false;
}
default:
return true;
}
}
I want to write this function with variadic templates so that it can handle any number of arguments in a type-safe way. I can see a solution using recursive functions, passing along the counter and the variadic index and comparing them for equality, but this would seem to yield far less efficient code than the switch statement above (a sequence of if-checks compared to a jump table).
Can this be done efficiently using template metaprogramming or do I need to provide overloads for each arity?
This solution may be the most efficient:
Here's a solution similar to max's, but it: a) clearly separates out the generic parts from the parts specific to the solution, and b) I show that clang fully optimizes it. The basic idea is to build a switch case at compile time, from a contiguous integer sequence. We do that like this:
The idea is that integer gets passed into the lambda as an integral constant type, so its usable in compile time contexts. To use this with the current problem, all we have to do is forward the variadic pack a tuple, and apply the usual tricks with index sequence:
We'll use this definition of
func2
to look at some assembly:Looking here: https://godbolt.org/g/6idVPS we notice the following instructions:
Looking down for that label, we find:
In other words, clang has both turned this into a jump table, and inlined all the calls to
func2
. This is not possible using a table of function pointers as some have suggested (at least I've never seen a compiler do it), in fact the only way to get assembly this good is via switch case, or with this technique + clang. Sadly gcc will not generate assembly quite as good, but still decent.Just for fun, I propose the following way
but I don't think is a efficient way as the switch way.
Theoretically you could do binary search of parameter index by yourself:
[live demo]
Also for fun, this might be a bit too convoluted
Which rolls a vtable in
f
and dispatches accordingly tog
.Live