【问题标题】:Order of evaluation of elements in list-initialization列表初始化中元素的评估顺序
【发布时间】:2012-12-27 19:37:08
【问题描述】:

other topic 中,@Dietmar 给出了这个解决方案:

template <typename... T>
std::tuple<T...> parse(std::istream& in) 
{
    return std::tuple<T...>{ T(in)... };
}

说明,

使用大括号初始化是有效的,因为在大括号初始化列表中参数的评估顺序是它们出现的顺序。 (强调我的)

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

在花括号初始化列表的初始化列表中,初始化子句,包括任何由包扩展 (14.5.3) 产生的子句,按照它们出现的顺序进行评估。也就是说,与给定初始化子句关联的每个值计算和副作用在初始化器列表的逗号分隔列表中与跟随它的任何初始化器子句关联的每个值计算和副作用之前进行排序。 [注意:无论初始化的语义如何,这种评估顺序都成立;例如,它适用于初始化器列表的元素被解释为构造函数调用的参数时,即使调用的参数通常没有顺序约束。 ——尾注]


所以我尝试使用以下代码对此进行测试:

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

我的测试代码做错了吗?我将代码更改为:

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.04.7.2 测试了我的代码。连ideone都给this output

这是编译器的错误吗?

【问题讨论】:

  • 这是一个 GCC 错误。 Clang 是正确的。
  • 您希望我们提出什么要求? “是的,由于您给出的报价,这是一个错误”。这不是今天说了两次吗?在@Dietmar 的问题和Dietmar 的问题中,引用、引用和示例都给出了从左到右的顺序。
  • @JohannesSchaub-litb:我只是确保这是编译器中的一个错误,并且我的测试代码绝对没有问题。
  • 在执行 gcc 的错误报告程序之前,我还会回来查看。

标签: c++ gcc c++11 initializer-list operator-precedence


【解决方案1】:

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

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

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

【讨论】:

猜你喜欢
  • 2010-12-08
  • 2017-04-03
  • 2010-11-17
  • 2019-01-05
  • 2023-03-03
  • 1970-01-01
  • 2015-08-10
相关资源
最近更新 更多