大括号的数量如何影响统一初始化?

How does the number of braces affect uniform initialization?

考虑以下代码片段:

#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
}

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

Overload resolution这样很好玩

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

    请注意,名义上的临时对象 从未创建 :在重载解析选择 f(const A&) 之后,即使对于不可复制的类型,引用也只是 initialized to refer to a, and this interpretation can apply

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

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