Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
668 views
in Technique[技术] by (71.8m points)

templates - Why does parameter pack expansion work differently with different C++ compilers?

Parameter pack expansion is reversed by the VS2015 compiler.

I have the following code:

#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;
}

When I run this code in XCode (clang-700.1.81), I get this result:

1
2
3
4

But the same code run in VS2015 produces this output:

4
3
2
1

Why are the parameter packs expanded differently depending on the compiler? Is there a way to fix it without checking the platform and compiler version? Doesn't the standard guarantee anything about expansion order?

question from:https://stackoverflow.com/questions/35702180/why-does-parameter-pack-expansion-work-differently-with-different-c-compilers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It's not the order of parameter pack expansion which is different, it's the order of function argument evaluation.

f_Swallow
(
    [&]()
    {

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

For sake of brevity, lets just give that lambda the name funcN where N is the parameter number. Given four arguments, the parameter pack will be expanded by any conforming compiler into this:

f_Swallow(func1(), func2(), func3, func4()) ;

The order of evaluation of function arguments is unspecified in C++. The compiler could evaluate them in-order (like your version of Clang), in reverse order (like your version of MSVC), or in any order it likes. You cannot count on the evaluation order.

To get what you want, you could put the expressions into a context in which the order of evaluation is specified. For example:

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;
}

In C++17, you'll be able to do the following with fold expressions:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...