Вопрос

I thought that expanding a parameter pack had the following behavior:

// for Args ... p
f(p)...;
// was equivalent to
f(p1); f(p2); ...; f(pn);

But I just found out that gcc (4.6, 4.7 and 4.8) does it the other way around:

f(pn); ...; f(p2); f(p1);

Whereas clang does it as I expected.

Is that a bug in GCC or are they both valid according to the standard?

Minimal example

#include <iostream>
#include <string>

template<typename T>
bool print(const unsigned index, const T& value){
  std::cerr << "Parameter " << index << " is " << value << std::endl; 
  return true;
}

template<typename ... Args>
void printAll(Args ... args){
  unsigned i = 0;
  [](...){}(print(i++, args)...);
}

int main(){
  int a = 1; float b = 3.14; std::string c("hello");
  printAll(a, b, c);
}

Compiling and executing:

$> clang++ -std=c++11 -o test test.cpp
$> ./test
Parameter 0 is 1
Parameter 1 is 3.14
Parameter 2 is hello
$> g++ -std=c++11 -o test test.cpp
$> ./test
Parameter 0 is hello
Parameter 1 is 3.14
Parameter 2 is 1

Answer

It didn't take long for Martinho Fernandes to spot the error here. The problem is the order of evaluation of parameters, which is not defined by the standard (1.9.3):

Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function).

Это было полезно?

Решение

Is the order for variadic template pack expansion defined in the standard?

Yes. The expanded elements are in an order that corresponds to the original order of the pack.

In the test, the expansion [](...){}(print(i++, args)...); is equivalent to: [](...){}(print(i++, a), print(i++, b), print(i++, c));.

The test is flawed in that it tests the order of evaluation of function arguments, which is a completely different matter. If you try and execute the expanded form presented above, you will observe the same behaviour. Or you would if the code didn't have undefined behaviour, since the variable i is incremented several times without the increments being sequenced.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top