I would like to do the following:
// function that depends on key to do stuff
template <int key>
void bar() {...}
template <int ...Keys>
void foo(int key) {
// WHAT SHOULD BE HERE?
}
std::cin >> key;
foo<1,3,5,7,9>(key);
such that it becomes
template <int ...Key>
void foo(int key) {
switch (key) {
case 1: bar<1>();break;
case 3: bar<3>();break;
case 5: bar<5>();break;
case 7: bar<7>();break;
case 9: bar<9>();break;
default: break;
}
}
How can I generate a switch statement that enumerates all variadic template arguments as an efficient switch statement without manually writing the switch statement?
CodePudding user response:
Compilers can turn chained-ifs into switch statements in assembly.
A binary fold like this:
( [&key]{
if(key==Keys) {
bar<Keys>();
return true;
}
return false;
}()||... );
does what you ask, down to the assembly:
Live example - change the #if clause between 0 and 1 to swap between hand-crafted and generated switch statements.
CodePudding user response:
You could use a parameter pack expansion with an empty/extra foo
to close the pack as in the example below.
#include <cstdio>
template <int key>
void bar() {
printf( "%d ", key );
}
template < typename = void >
void foo(int key ) {
}
template <int val, int... Keys >
void foo(int key ) {
if ( val == key ) bar<val>();
else {
foo<Keys...>(key);
}
}
int main() {
for ( int key = 0; key<10; key ) {
foo<1,3,5,7,9>(key);
}
}
It prints
Program returned: 0
Program stdout
1 3 5 7 9
Godbolt: https://godbolt.org/z/zE1cE9eob
CodePudding user response:
Following the example of the Yakk's answer, I propose the following solution that, using ternary and comma operators, avoid the lambda
template <int ...Keys>
void foo (int key) {
(void)((Keys == key ? (void)bar<Keys>(), 0 : 0), ...);
}
or, maybe better,
template <int ...Keys>
void foo (int key) {
(void)((Keys == key ? (void)bar<Keys>(), true : false) || ...);
}