为什么参数包扩展在不同的C++编译器中的工作方式不同?

ALE*_*NOV 38 c++ parameters templates c++11

参数包扩展由VS2015编译器反转.

我有以下代码:

#include <iostream>
#include <vector>


template <typename... T>
void f_Swallow(T &&...)
{
}

template <typename... T>
std::vector<int> f(T ...arg)
{
    std::vector<int> result;
    f_Swallow
    (
        [&]()
        {

            result.push_back(arg);
            return true;
        }
        ()...
    ) ;
    return result;
}


using namespace std;
int main()
{
    auto vec = f(1,2,3,4);

    for (size_t i = 0; i < vec.size(); ++i)
        cout << vec[i] << endl;
}
Run Code Online (Sandbox Code Playgroud)

当我在XCode(clang-700.1.81)中运行此代码时,我得到以下结果:

1
2
3
4
Run Code Online (Sandbox Code Playgroud)

但VS2015中运行的相同代码会产生此输出:

4
3
2
1
Run Code Online (Sandbox Code Playgroud)

为什么参数包根据编译器的不同而不同地扩展?有没有办法在不检查平台和编译器版本的情况下修复它?标准不保证扩展订单的任何内容吗?

Tar*_*ama 46

它不是参数包扩展的顺序不同,它是函数参数评估的顺序.

f_Swallow
(
    [&]()
    {

        result.push_back(arg);
        return true;
    }
    ()...
) ;
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,让刚刚给该拉姆达的名称funcN,其中N是参数号.给定四个参数,参数包将由任何符合标准的编译器扩展为:

f_Swallow(func1(), func2(), func3, func4()) ;
Run Code Online (Sandbox Code Playgroud)

函数参数的评估顺序在C++中未指定.编译器可以按顺序(如您的Clang版本),以相反的顺序(如您的MSVC版本)或按照其喜欢的任何顺序对它们进行评估.您不能指望评估订单.

要获得所需内容,可以将表达式放入指定评估顺序的上下文中.例如:

template <typename... T>
std::vector<int> f(T ...arg)
{
    std::vector<int> result;
    (void)std::initializer_list<int> { (result.push_back(arg), 0)... };
    return result;
}
Run Code Online (Sandbox Code Playgroud)

在C++ 17中,您将能够使用折叠表达式执行以下操作:

template <typename... T>
std::vector<int> f(T ...arg)
{
    std::vector<int> result;
    (result.push_back(arg), ...);
    return result;
}
Run Code Online (Sandbox Code Playgroud)


ALE*_*NOV 11

我想它也可以像这样写:

template <typename... T>
std::vector<int> f(T ...arg)
{
    std::vector<int> result{ arg... };
    return result;
}
Run Code Online (Sandbox Code Playgroud)

无需创建虚拟std :: initializer_list