是否在标准中定义了可变参数模板包扩展的顺序?

时间:2014-03-07 11:15:06

标签: c++ c++11 variadic-templates

我认为扩展parameter pack会产生以下行为:

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

但我刚刚发现gcc(4.6,4.7和4.8)反过来了:

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

而clang按照我的预期做到了。

这是GCC中的错误还是根据标准有效?

最小范例

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

编译并执行:

$> 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

应答

马丁霍费尔南德斯在这里发现错误没多久。问题是参数评估的顺序,而标准(1.9.3)没有定义:

  

抽象机的某些其他方面和操作在本国际标准中描述为   未指定(例如,评估函数参数的顺序)。

1 个答案:

答案 0 :(得分:12)

  

标准中是否定义了可变参数模板包扩展的顺序?

是。扩展元素的顺序与包的原始顺序相对应。

在测试中,展开[](...){}(print(i++, args)...);相当于:[](...){}(print(i++, a), print(i++, b), print(i++, c));

测试存在缺陷,因为它测试了函数参数的评估顺序,这是一个完全不同的问题。如果您尝试执行上面提到的扩展表单,您将观察到相同的行为。或者,如果代码没有未定义的行为,您将会这样做,因为变量i会增加几次而不会对增量进行排序。