列表初始化中元素的评估顺序

Naw*_*waz 21 c++ gcc operator-precedence initializer-list c++11

另一个主题中,@ Didmar给出了这个解决方案:

template <typename... T>
std::tuple<T...> parse(std::istream& in) 
{
    return std::tuple<T...>{ T(in)... };
}
Run Code Online (Sandbox Code Playgroud)

说明,

大括号初始化的使用起作用,因为大括号初始化列表中参数的求值顺序是它们出现的顺序.(强调我的)

C++标准(n3485)的相关文本是,

在braced-init-list的initializer-list中,initializer-clauses(包括pack扩展(14.5.3)产生的任何结果)按照它们出现的顺序进行评估.也就是说,与给定初始化子句相关联的每个值计算和副作用在每个值计算和副作用之前与在初始化列表的逗号分隔列表中跟随它之后的任何初始化子句相关联.[注意:无论初始化的语义如何,此评估顺序都保持不变; 例如,当initializer-list的元素被解释为构造函数调用的参数时,它适用,即使通常对调用的参数没有排序约束. - 尾注]


所以我尝试用以下代码测试它:

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);
}
Run Code Online (Sandbox Code Playgroud)

预期产量:

A1::data = A1
A2::data = A2
Run Code Online (Sandbox Code Playgroud)

实际产量:

A1::data = A2
A2::data = A1
Run Code Online (Sandbox Code Playgroud)

我的测试代码中有什么问题吗?我将代码更改为:

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
Run Code Online (Sandbox Code Playgroud)

与以前相同的输出.我用MinGW (GCC) 4.7.0和测试了我的代码4.7.2.即使是ideone也会提供此输出.

这是编译器中的错误吗?

Naw*_*waz 10

回答我自己的问题.删除问题不是一个好主意,因为将来可能会有同样的问题.

是.这是GCC编译器中的一个错误.

取自@Johannes Schaub对该问题的评论.

  • 请注意,Microsoft的Visual Studio 12(2013)具有相同的错误,我刚刚在https://connect.microsoft.com/VisualStudio/feedbackdetail/view/976911/braced-initializer-list-not-evaluated-left-to上报告了该错误. -对 (2认同)