我正在尝试创建一个可变参数模板函数,它按顺序读取元素(带索引)。例如,调用函数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
但是,此代码取决于读取函数的评估顺序。如何生成依赖于包扩展的索引(以避免未定义的行为)?
答案 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))>());
}