Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有不同签名的函数的枚举切换器_C++_Templates_Casting_Switch Statement_Variadic Templates - Fatal编程技术网

C++ 具有不同签名的函数的枚举切换器

C++ 具有不同签名的函数的枚举切换器,c++,templates,casting,switch-statement,variadic-templates,C++,Templates,Casting,Switch Statement,Variadic Templates,很多时候,我会遇到这样的情况:我有一个enum或int,并且我的函数在特定的enum值/整数上参数化。在运行时,我有一个用于调用特定函数的枚举/整数。通过一些代码,它应该更清晰: template<int i> struct MyTrait { void f(int) { return 999;} }; template<> struct MyTrait<1> { void f(int a, int b) { return 1; }

很多时候,我会遇到这样的情况:我有一个enum或int,并且我的函数在特定的enum值/整数上参数化。在运行时,我有一个用于调用特定函数的枚举/整数。通过一些代码,它应该更清晰:

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 
模板
结构MyTrait
{
void f(int){return 999;}
};
模板
结构MyTrait
{
void f(inta,intb){return 1;}
};
模板
结构MyTrait
{
静态常数=2;
void f(inta,intb,intc){return 100;}
};
模板
结构MyTrait
{
静态常数=3;
void f(int a){return 120;}
};
模板
int切换器(int值、Args…参数)
{
开关(值)
{
病例指数:
返回MyTrait::f(参数…);
案例2:
MyTrait::f(参数…);
案例3:
MyTrait::f(参数…);
违约:
0;
}
返回1;
}
//切换器(3,10)应该调用MyTrait::f
要举例说明为什么这会有用,请检查

我使用的是C++11,我已经实现了一些类似于我发布的链接中的cswitch的东西。现在的问题是,它只适用于具有相同签名的函数。我的目标是使它也能与具有不同签名的函数一起工作,就像示例的traits中的函数一样

这里的主要目标是性能:与交换机相同的速度。 当然,如果可以使用。。。开关中的运算符,返回(取决于参数)不同值的函数,或者如果命名标签gcc扩展是标准功能(唉,我还认为goto语句是最后的选择)

我尝试了几十种方法,但似乎都没有达到我想要的效果。。我开始认为目前这是不可能的。。别客气(我真的希望如此!!)反驳我

到目前为止,我找到的最接近的解决方案是创建一个跳转表,将参数存储到一个元组中,将该元组(地址)转换为void*,然后将其转换回traits中。但这里也有性能成本,我不完全确定这是否能产生UB

我将排除使用宏、C++17功能(理想情况下仅限于C++11)和非标准功能的解决方案


谢谢

如果您想维护您的
MyTrait
类,只需为每个专门化定义一个回退模板函数即可。
例如:

template<>
struct MyTrait<1> {
    template<typename... Args> static int f(Args&&...) { return {}; }
    static int f(int, int) { return 1; }
};
#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);
}
模板
结构MyTrait{
模板静态int f(Args&&…{return{};}
静态int f(int,int){return 1;}
};
请参见一个工作示例

如果您可以重构一点代码,就可以使用自由函数、标记分派和单个回退函数来避免编译错误。
例如:

template<>
struct MyTrait<1> {
    template<typename... Args> static int f(Args&&...) { return {}; }
    static int f(int, int) { return 1; }
};
#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);
}
#包括
#包括
模板
结构标记{};
intf(tag,int,int){return 1;}
intf(tag,int,int,int){return 100;}
intf(标记,int){std::cout decltype(f(std::forward(args)…){
返回f(标准::转发(参数)…);
}
模板
int调用者(char、Args&&…Args){
返回{};
}
模板
整型切换器(整型值、参数和参数){
开关(值){
案例1:
调用者(0,标记{},std::forward(参数)…);
打破
案例2:
调用者(0,标记{},std::forward(参数)…);
打破
案例3:
调用者(0,标记{},std::forward(参数)…);
打破
违约:
(无效)0;
}
返回1;
}
int main(){
开关(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);
}
#包括
#包括
#包括
模板结构标记:标记{};
模板结构标记{};
intf(tag,int,int){return 1;}
intf(tag,int,int,int){return 100;}
intf(tag,int){std::cout
调用者(标记t、int值、Args&…Args){
返回N==值?f(t,std::forward(args)…):调用者(标记{},value,std::forward(args)…);
}
模板
整型切换器(整型值、参数和参数){
返回调用者(标记{},值,std::forward(参数)…);
}
int main(){
开关(3,10);
}

如果你想继续你的
MyTrait
类,你可以这样做。它对你有用吗?有更好的解决方案,但你必须更改代码的设计。哎呀!找不到该页面。如果我们调用
切换器(3,42,42,“参数太多”),你想发生什么;
?@Jarod42问得好:我们在通话期间处于运行状态,因此可能会出现异常情况谢谢您的回复。您的解决方案确实有效,但我可能还不太清楚我想做什么。我正在尝试删除该开关,而您提出的解决方案有一个开关:)@user3770392-Answer-updated,它没有太长时间er现在是一个开关。;-…让我知道它现在是否适用于您。mate它似乎真的有效!我只想使用enable_if=typename std::enable_if::type;}来显示名称空间的详细信息{template现在我必须理解为什么这样做,以及与交换机相比是否有任何性能开销。但是,伙计,非常棒的解决方案!你认为这种方法也适用于traits样式吗?我已经运行了一些测试,没有进行太多优化,标记方法比标准switc慢23%Happroach@user3770392好吧,这是有道理的,在最坏的情况下,你有很多函数调用,而不是直接跳到正确的位置。你不能吃蛋糕,它也不能吃