在编译时构建交换机

Building a switch at compile time

本文关键字:交换机 构建 编译      更新时间:2023-10-16

简单的问题是:你能在编译时构建一个类似switch的东西吗?答案是肯定的。但是,我可以将类似这样的东西作为switch进行优化(或可能进行优化(吗?

解释这个问题:一个例子:

假设我有一个接受整数的函数,我希望它对每个整数输入执行不同的操作(行为(。这很简单,并且是使用switch的经典案例。但假设我有一个实现行为的类型的模板参数包,我想为这组行为编写等效的switch,并在包中键入它们的索引。当然,这很容易实现,下面有一个例子。

我的实现的问题是,即使在较低的优化级别,交换机也会编译成一个带有小跳转表的计算跳转。模板化的解决方案变成了一组简单的if/then/else-if/。。。子句,并且在给定足够高的优化设置的情况下以这种方式进行编译。

示例如下:

https://godbolt.org/g/fxQF1U

在该示例中,您可以在第690行的程序集中看到基于switch的实现。模板化版本可以在第804行找到。我在这里还包括了我的例子的源代码,以防链接失效。

我知道编译器可以根据"好像"子句进行尽可能多的优化,但有没有一种方法可以让编译器更有可能生成更优化的代码?

#include <tuple>
#include <type_traits>
#include <any>
#include <string>
#include <vector>
#include <typeinfo>
#include <iostream>
#include <random>
template <typename... T>
struct Types {};
template <int I>
std::any get_type_name2p(int n) {
return unsigned();
}
template <int I, typename T, typename... Rest>
std::any get_type_name2p(int n) {
if (n == I) {
return T();
}
return get_type_name2p<I + 1, Rest...>(n);
}
std::any get_type_name2(int n)
{
return get_type_name2p<
0, int, float, std::string, std::vector<int>,
std::vector<float>, std::vector<double>, double, char>(n);
}
std::any get_type_name(int n)
{
switch (n) {
case 0:
return int();
case 1:
return float();
case 2:
return std::string();
case 3:
return std::vector<int>();
case 4:
return std::vector<float>();
case 5:
return std::vector<double>();
case 6:
return double();
case 7:
return char();
default:
return unsigned();
}
}
int main()
{
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> dist(1, 10);
auto n = dist(mt);
auto x = get_type_name(n);
std::cout << x.type().name() << std::endl;
auto y = get_type_name2(n);
std::cout << y.type().name() << std::endl;
return 0;
}

这里有一个可能的解决方案:

std::any get_type_name(int n)
{
if ((n<0) || (n>7)) { n = 8; }
std::any types[9]=
{
int(),
float(),
std::string(),
std::vector<int>(),
std::vector<float>(),
std::vector<double>(),
double(),
char(),
unsigned()
};
return types[n];
}