我认为扩展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)没有定义:
抽象机的某些其他方面和操作在本国际标准中描述为 未指定(例如,评估函数参数的顺序)。
答案 0 :(得分:12)
标准中是否定义了可变参数模板包扩展的顺序?
是。扩展元素的顺序与包的原始顺序相对应。
在测试中,展开[](...){}(print(i++, args)...);
相当于:[](...){}(print(i++, a), print(i++, b), print(i++, c));
。
测试存在缺陷,因为它测试了函数参数的评估顺序,这是一个完全不同的问题。如果您尝试执行上面提到的扩展表单,您将观察到相同的行为。或者,如果代码没有未定义的行为,您将会这样做,因为变量i
会增加几次而不会对增量进行排序。