c++ – Questions about variadic template expansion and argument evaluation order.

Question:

class my_vector
    : private std::vector<int>
{
    template <std::size_t... Index>
    void func_1_(std::index_sequence<Index...>)
    {
        int n[] = { 0, (static_cast<void>(push_back(Index)), 0)... };
    }
    template <std::size_t... Index>
    void func_2_(std::index_sequence<Index...>)
    {
        [](auto&&...){}((static_cast<void>(push_back(Index)), 0)...);
    }
public:
    template <std::size_t N>
    void func_1()
    {
        func_1_(std::make_index_sequence<N>{});
    }
    template <std::size_t N>
    void func_2()
    {
        func_2_(std::make_index_sequence<N>{});
    }

    using std::vector<int>::begin;
    using std::vector<int>::end;
    using std::vector<int>::clear;
};

int main()
{
    my_vector v;
    for(auto& i : v)
    {
        std::cout << i;
    }

    v.func_1<10>();
    for(auto& i : v)
    {
        std::cout << i;
    }
    std::cout << std::endl;

    v.clear();
    for(auto& i : v)
    {
        std::cout << i;
    }

    v.func_2<10>();
    for(auto& i : v)
    {
        std::cout << i;
    }
    std::cout << std::endl;
}

It was output like this.

0123456789
9876543210

I expected it to be output like this.

0123456789
0123456789

Please tell me why the output on the second line is so.

Answer: Answer:

void func_2_(std::index_sequence<Index...>)
{
    [](auto&&...){}((static_cast<void>(push_back(Index)), 0)...);
}

Let me explain a little about this lambda function.

The order in which function arguments are evaluated (calculated) is unspecified due to the C ++ language specification. In other words, the compiler can evaluate the arguments in any order. It ’s a famous problem,

int i = 0;
f(++i, ++i, ++i);

So what about the value of the argument passed to the function f? The answer is, I don't know. It may be evaluated from the front and become (1, 2, 3). Since it is a pre-increment, it may be calculated together first to be (3, 3, 3). Even if you use the same compiler, they may be evaluated in a different order each time due to optimization reasons.

The same is true for lambda functions, and we don't know in what order the arguments are evaluated. In this code, 10 comma expressions (static_cast<void>(push_back(Index)), 0) are passed as arguments, but in what order these comma expressions are evaluated (= push_back in = in what order). I don't know if it will be done). It can be in a completely random order.

Most implementations push arguments from the back onto the stack by default. Perhaps the order was reversed because the compiler evaluated each argument on the stack one by one.

Scroll to Top