【问题标题】:How does the number of braces affect uniform initialization?大括号的数量如何影响统一初始化?
【发布时间】:2019-06-27 12:06:09
【问题描述】:

考虑以下代码sn-p:

#include <iostream>

struct A {
  A() {}
  A(const A&) {}
};

struct B {
  B(const A&) {}
};

void f(const A&) { std::cout << "A" << std::endl; }
void f(const B&) { std::cout << "B" << std::endl; }

int main() {
  A a;
  f(   {a}   ); // A
  f(  {{a}}  ); // ambiguous
  f( {{{a}}} ); // B
  f({{{{a}}}}); // no matching function
}

为什么每个调用都制造相应的输出?大括号的数量如何影响统一初始化?大括号省略对这一切有何影响?

【问题讨论】:

  • 完全被吸引了。但我认为你最好发布你的编译器消息。 :)
  • @Constructor cmets 在使用(至少)g++ 编译时给出错误消息,否则在执行期间写入的内容
  • 可能要加标签language-lawyer
  • Nit:成员函数定义后的分号毫无意义,让外行想象所有右大括号都应该加一个。
  • @Rakete1111:null statements 比 null declarations 有更多用途(它们也不是语句)。

标签: c++ c++11 language-lawyer uniform-initialization list-initialization


【解决方案1】:

Overload resolution这样好玩。

  1. {a} 具有 完全匹配 等级,用于初始化(临时)const A&amp; 参数,该参数优于用户定义的转换 B(const A&amp;) 作为 {a} 的实现。此规则是在 C++14 中添加的,用于解决列表初始化中的歧义(以及对聚合的调整)。

    请注意,名义上的临时是从未创建过:在重载决议选择f(const A&amp;) 后,引用只是initialized to refer to a,这种解释can apply 即使对于不可复制的类型也是如此。 p>

  2. 允许为ABB 的构造函数初始化const A&amp; 参数(如上)。
  3. 禁止像multiple user-defined conversions 一样重复调用复制构造函数(此处为A(const A&amp;)),而不是允许每个重载决议级别进行一次此类转换。因此,在第二种情况下,最外面的大括号必须从 A 中初始化一个 B,该 {{a}} 是从 {{a}} 初始化的(允许的)。 (大括号的中间层可以初始化一个B,但是外层复制它是被禁止的,没有其他东西可以尝试初始化。)
  4. 每种解释都涉及这种不允许的额外转换。

不涉及大括号省略——我们不知道允许它的最外层目标类型。

【讨论】:

  • 只是为了确保我理解正确:f({a}) 可以通过f(A{a})f(B{a}) 实现。由于第一个是完美匹配,因此它比第二个匹配更好,并且调用是明确的。现在我们考虑第二种情况。 f({{a}})可以通过f(A{A{a}})f(B{A{a}})f(B{B{a}})实现。第一个被禁止,第二个和第三个同样匹配,因此呼叫是模棱两可的。现在考虑第三种情况。 f({{{a}}})可以通过f(A{A{A{a}}})f(B{A{A{a}}})f(B{B{A{a}}})f(B{B{B{a}}})实现。只有第三种是不禁止的。
  • 我想我还没有理解它。如果问题是f(B{A{a}})f(B{B{a}}) 匹配得很好,那么当我们删除f(const A&amp;) 时调用仍然是模棱两可的。然而,编译器却说反了。
  • @user1494080:歧义在f(A{A{a}})(只有这两者的外部是用户定义的)和f(B{A{a}})之间。 f(B{B{a}}) 无效,因为内部转换是用户定义的,所以外部转换一定不是。注意不对称:{a} -&gt; A 是完全匹配的,但 resulting {B{a}} -&gt; B 是用户定义的,因为必须进行重载解析才能识别 {a} -&gt; B 转换。
  • f(A{A{a}}) 调用两次一次和相同的复制构造函数A(const A&amp;)?一个是用户定义的而另一个不是?
  • @DavisHerring 对不起,我还在挣扎。禁止f(B{B{a}}),因为内部转换是用户定义的(我同意),而外部转换也是用户定义的(我是这样理解你的)。但是第三种情况 f(B{B{A{a}}}) 是不禁止的,因为内部转换是完全匹配,中间转换是用户自定义,而外部又是标准转换?为什么第一个f(B{B{...}})是用户定义的,第二个f(B{B{...}})不是?
猜你喜欢
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
  • 2016-12-11
  • 2013-09-25
  • 2013-08-23
  • 1970-01-01
  • 2019-08-04
相关资源
最近更新 更多