To easily re-write a big switch-case, I’m trying constexpr function template like this (it’s only a simplified version with just cout):
#include <iostream>
template<int T>
constexpr void bigSwitchCase(const int idx)
{
if (T == 1 && T == idx)
{
std::cout << 1 <<std::endl;
return;
}
if (T == idx)
{
std::cout << T << std::endl;
}
else if (T > 1)
{
bigSwitchCase<T - 1>(idx);
}
return;
}
template<>
void bigSwitchCase<1>(const int idx)
{
if (1== idx)
{
std::cout << 1 <<std::endl;
return;
}
}
int main()
{
bigSwitchCase<64>(15);
//bigSwitchCase<4096>(15);
return 0;
}
but the problem is it is not producing as fast code as below version:
switch(idx)
{
case 1: std::cout << 1 << std::endl; break;
case 2: std::cout << 2 << std::endl; break;
...
case 4096: std::cout << 4096 << std::endl; break;
default:
}
because if-else parts in the constexpr function contains idx input which is not constexpr hence the if-else can not be made constxpr. But the switch-case elements are all cosntants.
So, the function produces a loop instead and checks against idx value, according to compiler-generated assembly codes. I need it to directly jump to the point that does the work instead of looping.
How to produce efficient code using only constexpr function templates (because real work includes plain arrays with compile-time sizes) with a run-time integer input (about ~4000 upper limit and 1 lower limit)?
>Solution :
You can give the compiler a hint that you want a jump table instead of iteration through all cases by implementing it in that form yourself:
template<int I>
void doit()
{
std::cout << I <<std::endl;
return;
}
template<int N>
void bigSwitchCase(int idx) {
static constexpr auto jumptable =
[]<int... Is>(std::integer_sequence<int, 0, Is...>){
return std::array{doit<Is>...};
}(std::make_integer_sequence<int, N+1>());
if(idx >= 1 && idx <= N)
jumptable[idx-1]();
}