c++ 如何使用constexpr函数模板高效地重写一个很长的switch-case?

5kgi1eie  于 2023-05-30  发布在  其他
关注(0)|答案(1)|浏览(187)

为了方便地重写一个大的switch-case,我尝试了constexpr函数模板,如下所示(它只是一个简化的版本,只有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;
}

但问题是它并没有像下面的版本那样产生快速的代码:

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:
}

因为constexpr函数中的if-else部分包含不是constexpr的idx输入,因此不能使if-else成为constexpr。但开关盒元素都是常量。
因此,根据编译器生成的汇编代码,该函数会生成一个循环并检查idx值。我需要它直接跳到做工作的点,而不是循环。
如何仅使用constexpr函数模板(因为真实的工作包括具有编译时大小的普通数组)和运行时整数输入(约4000上限和1下限)生成高效代码?

72qzrwbm

72qzrwbm1#

你可以给予编译器一个提示,你想要一个跳转表,而不是通过自己实现的形式来迭代所有的情况:

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]();
}

相关问题