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

查看:234
本文介绍了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天全站免登陆