Variadic模板包扩展参数id

时间:2015-03-18 10:30:01

标签: c++ c++11 variadic-templates

我正在尝试创建一个可变参数模板函数,它按顺序读取元素(带索引)。例如,调用函数read_tuple读取id为0和1的两个int(使用read_int(0)和read_int(1))。

以下是我到目前为止的代码:

int data[] = {10,20,30,40};

int int_read(int id)
{
    return data[id];
}

template <typename T>
T read(int& index)
{
    index--;
    int value = int_read(index);
    std::cout << "index :" << index << " value: " << value << std::endl;
    return value;
}

template <typename... Args>
std::tuple<Args...> read_tuple()
{
    int index = sizeof...(Args);
    return std::tuple<Args...>(read<Args>(index)...);
}

我可以这样称呼它:

auto tuple = read_tuple<int, int>();
std::cout << "First: " << std::get<0>(tuple) << std::endl;

我得到以下输出:

index :1 value: 20
index :0 value: 10
First: 10

但是,此代码取决于读取函数的评估顺序。如何生成依赖于包扩展的索引(以避免未定义的行为)?

1 个答案:

答案 0 :(得分:3)

正如Piotr指出的那样,如果你使用braced-init-list,评估的顺序是有保障的。但是如果你在4.9.1之前使用GCC,要小心,因为它不起作用(c.f。Evaluation order (sequenced-before relation) among initializer-clauses in braced-init-list)。

如果您使用的版本不保证初始化顺序(或者只是想生成ID),您可以使用索引器(来自other stackoverflow post):

template<int... I> struct index {
    template<int n> using append = index<I..., n>;
};
template<int N> struct make_index {
    typedef typename make_index<N - 1>::type::template append<N - 1> type;
};
template<> struct make_index<0> { typedef index<> type; };
template<int N> using indexer = typename make_index<N>::type;

你可以这样使用它:

int data[] = {10,20,30,40};

int int_read(int id)
{
    return data[id];
}

template <typename T>
T read(int index)
{
    int value = int_read(index);
    std::cout << "index :" << index << " value: " << value << std::endl;
    return value;
}

template <typename... Args, int... i>
std::tuple<Args...> read_tuple_indexed(index<i...>)
{
    return std::tuple<Args...>(read<Args>(i)...);
}

template <typename... Args>
std::tuple<Args...> read_tuple()
{
    return read_tuple_indexed<Args...>(indexer<(sizeof...(Args))>());
}