C++/C++11 - 可变参数模板的 Switch 语句? [英] C++/C++11 - Switch statement for variadic templates?

查看:29
本文介绍了C++/C++11 - 可变参数模板的 Switch 语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一些这样的结构:

Let's say I have a few structs like this:

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

};

如您所见,对于所有三个结构,我可以在该结构的一个对象上调用 DoSomething() 并让它工作(尽管每个结构的实现方式不同):

As you can see, for all three structs, I can call DoSomething() on an object of that struct and have it work (though this is achieved differently for each struct):

MyStruct1 a;
MyStruct2 b;
MyStruct3 c;

a.DoSomething(); // works, calls Struct1's instance function
b.DoSomething(); // works, calls Struct2's static function, discards return value
c.DoSomething(); // works, calls Struct3's function pointer

现在,假设我将这些结构的任意选择放入一个元组中:

Now, let's say I put an arbitrary selection of these structs into a tuple:

tuple<MyStruct2, MyStruct3, MyStruct2, MyStruct1> collection;

假设我想要获取其中一个元素并根据运行时确定的索引运行其 DoSomething() 函数.为此,我可以使用 switch 语句:

Let's also say that I want to take one of those elements and run its DoSomething() function based on an index that is determined at runtime. To achieve this, I could use a switch statement:

switch(index) {

case 0: get<0>(collection).DoSomething(); break;
case 1: get<1>(collection).DoSomething(); break;
case 2: get<2>(collection).DoSomething(); break;
case 3: get<3>(collection).DoSomething(); break;

}

这工作得很好而且很花哨,但是当需要处理多个不同排列的(并且可能比 4 元素长得多的)元组时,它会变得非常乏味、重复且容易出错.如果可以根据可变参数模板中的元素数量自动生成 switch 语句,那将非常方便.伪代码:

This works fine and dandy, but gets very tedious, repetitive and error-prone when it needs to be done with multiple differently arranged (and potentially much longer than 4-element) tuples. It would be very handy if a switch statement could be automatically generated based on the number of elements in a variadic template. Pseudocode:

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

    switch(index) {

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

    }

}

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

Is there any mechanism in C++11 that would allow me to achieve this? If not, I know I can undoubtedly hack together a solution with a list of function pointers within a template, but I'm just curious if something like this exists, since it would be better suited for my purposes. I'm sure a switch statement's compiler-generated jump list would be more efficient than my homemade function pointer solution as well.

推荐答案

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

You can use an array to bridge compile-time and runtime: (ab)use variadic templates to statically initialize the array elements, and then index into the array with the runtime parameter. The tricky part is finding the right element type for the array. In addition since we need the template to be variadic on the tuple indices rather than on the tuple elements I'll be using my usual trick.

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{});
}

这篇关于C++/C++11 - 可变参数模板的 Switch 语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆