9

这个问题与下面转载的代码片段有关:

struct A { 
    A():b(0) { } 
    A(const A&, int b = 0):b(b) { } 
    int b; 
};

int main() {
  A a;

  const A& a1 = { a };  
  const A& a2 = { a, 1 };
  a.b = 2;   
  std::cout << a1.b << a2.b << std::endl;
}

a1 赋值的右侧可以是构造中的单个值或构造中的参数列表。标准中是否有任何地方指定哪种解释优先?对于a2,它是一个临时A的构造,其地址分配给a2,如果我没有误解的话。

顺便说一句,在 Coliru 中通过 clang++ 编译此代码产生了输出 21。 gcc++-4.8 输出 01。

4

2 回答 2

5

由于缺陷报告,自 C++11 标准发布以来,列表初始化的定义发生了相当大的变化。

来自草案 n3485(标准发布后,有一些更正但没有 C++1y 特性)[dcl.init.list]/3

类型的对象或引用的列表初始化T定义如下:

  • 如果T是一个聚合 [...]
  • 否则,如果初始化列表没有元素 [...]
  • 否则,如果Tstd::initializer_list<E>[...]
  • 否则,如果T是类类型 [...]
  • 否则,如果初始化列表有一个类型的元素E并且T不是引用类型或其引用类型与引用相关E,则从该元素初始化对象或引用;如果需要进行缩小转换以将元素转换为T,则程序格式错误。
  • 否则,如果T是引用类型,则所引用类型的纯右值临时T被列表初始化,并且引用绑定到该临时
  • [...]

在委员会的 github 存储库 (ce016c64dc) 的最新草案中,此处仅对一点 [dcl.init.list]/3 进行了轻微更改:

  • 否则,如果T是引用类型,则所引用类型的纯右值临时T是复制列表初始化或直接列表初始化,具体取决于引用的初始化类型,并且引用绑定到该临时。

来自草案 n3242(在标准之前)[dcl.init.list]/3:

类型的对象或引用的列表初始化T定义如下:

  • 如果初始化列表没有元素 [...]
  • 否则,如果T是一个聚合 [...]
  • 否则,如果Tstd::initializer_list<E>[...]
  • 否则,如果T是类类型 [...]
  • 否则,如果T是对类类型的引用,或者如果T是任何引用类型并且初始化列表没有元素,则引用类型的纯右值临时T是列表初始化的,并且引用绑定到该临时。
  • [...]

(我现在没有标准本身的副本。)


假设您的编译器实现了对缺陷报告的建议解决方案。然后,第一个例子

const A& a1 = { a };

初始化为const A& a1 = a;(非临时);第二个例子

const A& a2 = { a, 1 };

初始化为const A& a2 = A(a,1);.

于 2013-10-24T19:31:28.413 回答
1

8.5.4/3类型 T 的对象或引用的列表初始化定义如下:
...

  • 否则,如果 T 是引用类型,则 T 引用的类型的纯右值临时是列表初始化的,并且引用绑定到该临时。

在您的示例中,a1不直接绑定到a,而是绑定到从a.

于 2013-10-24T19:30:28.587 回答