Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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
Templates C++/C++;11-可变模板的开关语句?_Templates_Metaprogramming_Switch Statement_C++11_Variadic - Fatal编程技术网

Templates C++/C++;11-可变模板的开关语句?

Templates C++/C++;11-可变模板的开关语句?,templates,metaprogramming,switch-statement,c++11,variadic,Templates,Metaprogramming,Switch Statement,C++11,Variadic,假设我有一些类似的结构: struct MyStruct1 { inline void DoSomething() { cout << "I'm number one!" << endl; } }; struct MyStruct2 { static int DoSomething() { cout << "I'm the runner up." << endl; r

假设我有一些类似的结构:

struct MyStruct1 {

    inline void DoSomething() {
        cout << "I'm number one!" << endl;
    }

};

struct MyStruct2 {

    static int DoSomething() {

        cout << "I'm the runner up." << endl;
        return 1;

    }

};

struct MyStruct3 {

    void (*DoSomething)();

    MyStruct3() {
        DoSomething = &InternalFunction;
    }

    static void InternalFunction() {
        cout << "I'm the tricky loser." << endl;
    }

};
template<int N, typename ...Args>
struct call_N_helper
{
  static void call(const std::tuple<Args...> & t, int i)
  {
    if (i == N) std::get<N>(t).call();
    else call_N_helper<N-1, Args...>(t, i);
  }
};

template<typename ...Args>
struct call_N_helper<0, Args...>
{
  static void call(const std::tuple<Args...> & t, int i)
  {
    if (i == 0) std::get<0>(t).call();
  }
};

template<typename ...Args>
void call_N(const std::tuple<Args...> & t, int i)
{
  call_N_helper<sizeof...(Args), Args...>::call(t, i);
}
现在,假设我将这些结构的任意选择放入一个元组:

tuple<MyStruct2, MyStruct3, MyStruct2, MyStruct1> collection;
这种方法很好用,但当需要使用多个不同排列(可能比4元素长得多)的元组时,会变得非常乏味、重复和容易出错。如果可以根据可变模板中的元素数量自动生成switch语句,这将非常方便。伪代码:

template <typename... T>
void DoSomethingByIndex(int index, tuple<T...>& collection) {

    switch(index) {

    STATIC_REPEAT(sizeof...(T), X) {
    case X: get<X>(collection).DoSomething(); break;
    }

    }

}
模板
void DoSomethingByIndex(整数索引、元组和集合){
开关(索引){
静态重复(尺寸…(T),X){
案例X:get(collection.DoSomething();break;
}
}
}

C++11中是否有任何机制允许我实现这一点?如果没有,我知道我可以毫无疑问地在一个模板中用函数指针列表拼凑出一个解决方案,但我只是好奇这样的东西是否存在,因为它更适合我的目的。我确信switch语句的编译器生成的跳转列表也会比我自制的函数指针解决方案更有效。

Hmmm,我很想尝试以下方法:

struct MyStruct1 {

    inline void DoSomething() {
        cout << "I'm number one!" << endl;
    }

};

struct MyStruct2 {

    static int DoSomething() {

        cout << "I'm the runner up." << endl;
        return 1;

    }

};

struct MyStruct3 {

    void (*DoSomething)();

    MyStruct3() {
        DoSomething = &InternalFunction;
    }

    static void InternalFunction() {
        cout << "I'm the tricky loser." << endl;
    }

};
template<int N, typename ...Args>
struct call_N_helper
{
  static void call(const std::tuple<Args...> & t, int i)
  {
    if (i == N) std::get<N>(t).call();
    else call_N_helper<N-1, Args...>(t, i);
  }
};

template<typename ...Args>
struct call_N_helper<0, Args...>
{
  static void call(const std::tuple<Args...> & t, int i)
  {
    if (i == 0) std::get<0>(t).call();
  }
};

template<typename ...Args>
void call_N(const std::tuple<Args...> & t, int i)
{
  call_N_helper<sizeof...(Args), Args...>::call(t, i);
}
模板
结构调用\u N\u帮助程序
{
静态void调用(const std::tuple&t,int i)
{
if(i==N)std::get(t).call();
否则称之为帮助者(t,i);
}
};
模板
结构调用\u N\u帮助程序
{
静态void调用(const std::tuple&t,int i)
{
如果(i==0)std::get(t).call();
}
};
模板
无效调用(常量std::tuple&t,int i)
{
call\N\u helper::call(t,i);
}

这只是一个未经测试的想法。

您可以使用数组连接编译时和运行时:(ab)使用可变模板静态初始化数组元素,然后使用运行时参数索引到数组中。棘手的部分是为数组找到正确的元素类型。另外,由于我们需要模板在元组索引上是可变的,而不是在元组元素上,所以我将使用我通常的技巧

template<int... Indices>
struct indices {
    typedef indices<Indices..., sizeof...(Indices)> next;
};

template<int N>
struct build_indices {
    typedef typename build_indices<N - 1>::type::next type;
};

template<>
struct build_indices<0> {
    typedef indices<> type;
};

// No need to be variadic on the tuple elements as we don't care about them
// So I'm using perfect forwarding for the tuple
template<typename Tuple, int... Indices>
void
do_something_by_index(Tuple&& tuple, int index, indices<Indices...>)
{
    using std::get;

    typedef void (*element_type)(Tuple&&);
    static constexpr element_type table[] = {
        [](Tuple&& tuple)
        { get<Indices>(std::forward<Tuple>(tuple)).DoSomething(); }
        ...
    };

    table[index](std::forward<Tuple>(tuple));
}

// Proverbial layer of indirection to get the indices
template<typename Tuple>
void
do_something_by_index(Tuple&& tuple, int index)
{
    typedef typename std::decay<Tuple>::type decay_type;
    constexpr auto tuple_size = std::tuple_size<decay_type>::value;
    typedef typename build_indices<tuple_size>::type indices_type;

    do_something_by_index(std::forward<Tuple>(tuple), index, indices_type{});
}
模板
结构索引{
然后键入def索引;
};
模板
结构构建索引{
typedef typename build_index::type::next type;
};
模板
结构构建索引{
类型定义索引类型;
};
//不需要对元组元素进行可变,因为我们不关心它们
//所以我对元组使用完美转发
模板
无效的
按索引做某事(元组和元组、整数索引、索引)
{
使用std::get;
typedef void(*元素类型)(元组&&);
静态constexpr元素类型表[]={
[](元组和元组)
{get(std::forward(tuple)).DoSomething();}
...
};
表[索引](标准::转发(元组));
}
//获取索引的间接层
模板
无效的
按索引做某事(元组和元组,int索引)
{
typedef typename std::decay::type decay_type;
constexpr auto tuple_size=std::tuple_size::value;
typedef typename build_index::type index_type;
通过索引(std::forward(tuple)、索引、索引类型{})做某事;
}

我不确定我是否理解switch语句的需要…为什么不使用索引调用get并调用
DoSomething()
?模板参数必须是编译时常量。索引是在运行时确定的。啊,我明白了。。。这是一个元组。您是被迫使用元组的吗?我可以设想其他技术使用继承和指向基本结构的指针的单独列表,但在这种情况下,我认为它们的复杂性和性能影响(尽管公认很小)将超过简单地使用函数指针列表编写模板,这并不是什么大问题。主要是我想知道,在C++11中是否有一个隐藏在某处的银弹,它可以提供令人敬畏的性能,而无需我编写任何东西。:-)您是否想过使用
std::function
而不是原始函数指针?像g++这样的编译器是否可能将if-else转换为switch语句并最终转换为跳转表?@nonoitall:这有关系吗?你为什么这么在意这部电影的表现?一个
std::vector
可能在速度上几乎相同。@nonoitall:为什么不测试一下呢?启动编译器并检查程序集输出…看起来不像。即使元组中有-O3和30多个元素,它仍然会产生一系列与元素数量成比例的比较。@Nicol Bolas:这比其他任何东西都更令人好奇。我只是想知道是否有比手工制作的函数指针表更快更优雅的东西。理论上应该是switch语句,但是语法是否存在以创建可变语句?包扩展的最佳使用:-)创建函数指针表的有趣方式!使用了很多我不知道或想不到的功能。G++在使用lambda函数时遇到了瓶颈(“参数包未扩展为“…”),但我使用了单独的模板函数。(关于如何使它与lambda函数一起工作,有什么想法吗?)。它完成了什么?通过头文件挖掘并推断出std::decation::type基本上只返回“裸”类型,没有附加引用、指针、常量或挥发份。是吗?@nonoitall我的GCC 4.7快照也无法处理lambda的扩展,我也不太想检查我是否正确或者编译器是否正确——谢天谢地,您找到的解决方法是可以接受的。在这种情况下,get(collection)。DoSomething()不会内联。我的意思是存储指向lambdas的指针,而switch语句允许编译器内联所有内容。