Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
741 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 Reply

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...