列表初始化中元素的评估顺序
在另一个话题中 ,@Dietmar给出了这个解决scheme:
template <typename... T> std::tuple<T...> parse(std::istream& in) { return std::tuple<T...>{ T(in)... }; }
说明,
使用大括号初始化工作是因为大括号初始化符列表中的参数的评估 顺序是它们出现的顺序 。 (强调我的)
C ++标准(n3485)的相关文本是,
在braced-init-list的初始化程序列表中,初始化程序子句(包括从程序包扩展(14.5.3)产生的任何子程序子句)按其出现的顺序进行评估。 也就是说,与给定初始化子句相关联的每个值计算和副作用在与初始值设定项列表的逗号分隔列表中的任何初始化子句相关联的每个值计算和副作用之前被sorting。 [注意:不pipe初始化的语义如何,这个评估顺序都是成立的。 例如,当初始化列表的元素被解释为构造函数调用的参数时,即使通常对调用的参数没有sorting约束,也适用。 – 注意]
所以我试图用下面的代码来testing它:
template<int N> struct A { std::string data; A(std::istream & stream) { stream >> data; } friend std::ostream& operator<<(std::ostream & out, A<N> const & a) { return out << "A"<<N<<"::data = " << a.data; } }; typedef A<1> A1; typedef A<2> A2; template<typename ...Args> void test(std::istream & stream) { std::tuple<Args...> args { Args(stream)... }; std::cout << std::get<0>(args) << std::endl; std::cout << std::get<1>(args) << std::endl; } int main() { std::stringstream ss("A1 A2"); test<A1,A2>(ss); }
预期产出:
A1::data = A1 A2::data = A2
实际输出:
A1::data = A2 A2::data = A1
我在testing代码中做错了什么? 我改变了我的代码:
std::stringstream ss("A1 A2"); std::tuple<A1,A2> args{A1(ss), A2(ss)}; std::cout << std::get<0>(args) << std::endl; std::cout << std::get<1>(args) << std::endl
与以前相同的输出。 我用MinGW (GCC) 4.7.0
和4.7.2
testing了我的代码。 甚至ideone也提供这个输出 。
这是编译器中的错误吗?
回答我自己的问题。 删除问题不是一个好主意,因为将来有人可能会有同样的问题。
是。 这是GCC编译器中的一个错误。
- Bug 51253 – [C ++ 11] [DR 1030] braced-init-list中initializer-clause之间的评估顺序
来自@Johannes Schaub对这个问题的评论。