很多时候,碰巧会发现我有一个枚举或一个int的情况,并且我有在特定的枚举值/整数上参数化的函数。在运行时,我有一个枚举/整数,用于调用特定的函数。使用一些代码,它应该更清晰:
template<int i>
struct MyTrait
{
void f(int) { return 999;}
};
template<>
struct MyTrait<1>
{
void f(int a, int b) { return 1; }
};
template<>
struct MyTrait<2>
{
static const int ARD = 2;
void f(int a, int b, int c) { return 100;}
};
template<>
struct MyTrait<3>
{
static const int ARD = 3;
void f(int a) { return 120;}
};
template<class... Args>
int switcher(int value, Args... arguments)
{
switch(value)
{
case indices:
return MyTrait<1>::f(arguments...);
case 2:
MyTrait<2>::f(arguments...);
case 3:
MyTrait<3>::f(arguments...);
default:
0;
}
return 1;
}
// switcher(3, 10) should call MyTrait<3>::f
为了举例说明为什么这很有用,请检查here
我正在使用C++ 11,并且实现了类似于我发布的链接中介绍的cswitch的东西。问题在于,目前,它仅适用于具有相同签名的功能。相反,我的目标是使它也可以与具有不同签名的函数一起使用,例如示例特征中的签名。
这里的主要目标是性能:与交换机相同的速度。
当然,如果可以在开关中使用...运算符,返回(取决于参数)不同值的函数,或者命名标签gcc扩展名是标准功能,那么一切都将非常容易。 ”还认为goto语句是不得已的方法。
我已经尝试了数十种方法,但是似乎没有我想要的方法。.我开始认为,目前这是不可能的。.随意(我真的希望它!)与我矛盾。
到目前为止,我找到的最接近的解决方案是创建一个跳转表,将参数存储到一个元组中,将该元组(地址)转换为void *,然后将其转换回特征。但是这里也有性能成本,我不确定这是否会产生UB。
我将排除使用MACROS,C++ 17功能(理想情况下仅为C++ 11)和非标准功能的解决方案。
谢谢
最佳答案
如果要维护MyTrait
类,则可以为每个特化定义回退模板函数。
举个例子:
template<>
struct MyTrait<1> {
template<typename... Args> static int f(Args&&...) { return {}; }
static int f(int, int) { return 1; }
};
请参见here一个工作示例。
如果您可以重构代码,则可以使用自由函数,标记分派(dispatch)和单个后备函数来避免编译错误。
举个例子:
#include<iostream>
#include<utility>
template<int>
struct tag {};
int f(tag<1>, int, int) { return 1; }
int f(tag<2>, int, int, int) { return 100;}
int f(tag<3>, int) { std::cout << "&"; return 120; }
template<typename... Args>
auto caller(int, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
template<typename... Args>
int caller(char, Args&&... args) {
return {};
}
template<class... Args>
int switcher(int value, Args&&... arguments) {
switch(value) {
case 1:
caller(0, tag<1>{}, std::forward<Args>(arguments)...);
break;
case 2:
caller(0, tag<2>{}, std::forward<Args>(arguments)...);
break;
case 3:
caller(0, tag<3>{}, std::forward<Args>(arguments)...);
break;
default:
(void)0;
}
return 1;
}
int main() {
switcher(3, 10);
}
编辑
在此评论之后:
我提议的是经过稍微修改的版本,不再需要切换,而是依赖于递归和继承:
#include <type_traits>
#include<iostream>
#include<utility>
template<int N> struct tag: tag<N-1> {};
template<> struct tag<0> {};
int f(tag<1>, int, int) { return 1; }
int f(tag<2>, int, int, int) { return 100;}
int f(tag<3>, int) { std::cout << "&"; return 120; }
template<typename... Args>
int f(Args&&...) { return {}; }
template<int N, typename... Args>
std::enable_if_t<(N == 0), int>
caller(tag<N> t, Args&&... args) {
return f(t, std::forward<Args>(args)...);
}
template<int N, typename... Args>
std::enable_if_t<(N > 0), int>
caller(tag<N> t, int value, Args&&... args) {
return N == value ? f(t, std::forward<Args>(args)...) : caller(tag<N-1>{}, value, std::forward<Args>(args)...);
}
template<class... Args>
int switcher(int value, Args&&... arguments) {
return caller(tag<3>{}, value, std::forward<Args>(arguments)...);
}
int main() {
switcher(3, 10);
}
关于c++ - 枚举切换器,用于具有不同签名的功能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43123243/