Home > database >  Convert variadic template ints to switch statement
Convert variadic template ints to switch statement

Time:01-19

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) || ...);
}
  • Related