Variadic模板功能解压缩顺序

nik*_*ack 3 c++ variadic-templates c++11

我有这个代码:

template<typename ...T>
struct Test
{
    void call(string str)
    {
        abc(get<T>(str)...);
    }

    template<typename U>
    string get(string& inp)
    {
        string ret{ inp[0] };
        inp.erase(0, 1);

        cout << ret << endl; // first "a", next "b", next "c" - everything is ok

        return ret;
    }

    void abc(string a, string b, string c)
    {
        cout << a << " " << b << " " << c << endl; // "b c a" - why?
    }
};
Run Code Online (Sandbox Code Playgroud)

我这样称呼它:

Test<int, bool, float> test;
test.call("abc");
Run Code Online (Sandbox Code Playgroud)

输出被b c a认为是我期待的a b c.此外,在get()功能我有一个正确的顺序.为什么是这样?我找不到关于这个订单的任何规则.

Tar*_*ama 5

函数参数的评估顺序未指定.

abc(get<T>(str)...);
Run Code Online (Sandbox Code Playgroud)

这基本上与:

abc(get<T1>(str), get<T2>(str), get<TN>(str));
Run Code Online (Sandbox Code Playgroud)

您可以通过生成用于存储字符串的数组,然后从该数组调度来强制执行评估顺序:

template <std::size_t N, std::size_t... Idx>
void call_helper(std::array<std::string, N> arr, std::index_sequence<Idx...>) {
    abc(std::get<Idx>(arr)...);
}

void call(string str)
{
    std::array<std::string,sizeof...(T)> arr { get<T>(str)... }; 
    call_helper(arr, std::index_sequence_for<T...>{});
}
Run Code Online (Sandbox Code Playgroud)

  • @nikitablack是的,那些`std :: get`调用的评估顺序是未指定的,但这并不重要.他们只是获得数组的第N个元素,它们没有任何副作用.所有处理都已在阵列的生成中完成. (2认同)
  • @nikitablack以这种方式思考它会有所帮助:在函数调用中对相同数据进行变异操作(更改其数据的操作)是一个坏主意*,因为我们没有订单.所以没有'pop`或`push`或`++` - 这些都很糟糕.非变异操作,如`get`,`front`,`[i]`非常无问题.(一些变异操作不关心顺序,但要小心 - 即,`set.insert(x)`是安全的,但是很可怕.)知道*为什么*函数参数中的变异是坏的是有用的,但是经验法则(变异=危险)使人们更容易思考. (2认同)