我将尝试解释标准的内容,而不是解释编译器的行为。
主要示例
要从{{{"test"}}} 直接初始化b1,重载决议适用于选择B 的最佳构造函数。因为没有从{{{"test"}}} 到B& 的隐式转换(列表初始值设定项不是左值),所以构造函数B(B&) 不可行。然后我们关注构造函数B(A),看看是否可行。
要确定从{{{"test"}}} 到A 的隐式转换顺序(为了简单起见,我将使用符号{{{"test"}}} -> A),重载决议适用于选择A 的最佳构造函数,所以我们需要根据[over.match.list]/1比较{{"test"}}->const char*和{{"test"}}->std::string(注意最外层大括号被省略):
当非聚合类类型 T 的对象被列表初始化,使得 [dcl.init.list] 指定根据本节中的规则执行重载解析时,重载解析分两个阶段选择构造函数:
...在复制列表初始化中,如果选择了显式构造函数,则初始化格式错误。
请注意,无论说明符 explicit 是什么,这里都会考虑所有构造函数。
{{"test"}} -> 根据[over.ics.list]/10 和[over.ics.list]/11,const char* 不存在:
否则,如果参数类型不是类:
如果初始化列表有一个元素本身不是初始化列表...
如果初始化列表没有元素...
在除上述列举的情况之外的所有情况下,都无法进行转换。
要确定{{"test"}} -> std::string,采用相同的过程,重载解析选择std::string的构造函数,该构造函数接受const char*类型的参数。
因此,{{{"test"}}} -> A 是通过选择构造函数 A(std::string) 来完成的。
变化
如果explicit 被删除会怎样?
过程不会改变。 GCC 将选择构造函数 A(const char*),而 Clang 将选择构造函数 A(std::string)。我认为这是 GCC 的一个错误。
如果b1的初始化器中只有两层大括号呢?
注意{{"test"}} -> const char* 不存在,但{"test"} -> const char* 存在。所以如果b1的初始化器中只有两层大括号,则选择构造函数A(const char*),因为{"test"}->const char*优于{"test"}->std::string。结果,在copy-list-initialization中选择了显式构造函数(构造函数B(A)中的参数A从{"test"}初始化),那么程序是病态的。
如果声明了构造函数B(const B&)怎么办?
请注意,如果 B(B&) 的声明被删除,也会发生这种情况。这次我们需要比较{{{"test"}}} -> A和{{{"test"}}} -> const B&,或者{{{"test"}}} -> const B等价。
要确定{{{"test"}}} -> const B,采用上述过程。我们需要比较 {{"test"}} -> A 和 {{"test"}} -> const B&。注意{{"test"}} -> const B& 根据[over.best.ics]/4 不存在:
但是,如果目标是
——构造函数的第一个参数或
——用户定义的转换函数的隐式对象参数
而构造函数或用户定义的转换函数是候选者
——[over.match.ctor],当参数是类复制初始化第二步中的临时参数时,
- [over.match.copy]、[over.match.conv] 或 [over.match.ref](在所有情况下),或
——[over.match.list]的第二阶段,当初始化列表恰好有一个元素本身就是初始化列表,并且目标是类X的构造函数的第一个参数,并且转换是 X 或
参考 cv X,
不考虑用户定义的转换序列。
为了确定{{"test"}} -> A,再次进行上述过程。这与我们在上一小节中讨论的情况几乎相同。结果,构造函数A(const char*) 被选中。注意这里选择构造函数来确定{{{"test"}}} -> const B,实际并不适用。尽管构造函数是显式的,但这是允许的。
因此,{{{"test"}}} -> const B 是通过选择构造函数 B(A),然后是构造函数 A(const char*) 来完成的。现在{{{"test"}}} -> A 和{{{"test"}}} -> const B 都是用户定义的转换序列,两者都不比另一个更好,所以b1 的初始化是模棱两可的。
如果括号被大括号代替怎么办?
根据前面小节中引用的[over.best.ics]/4,不考虑用户定义的转换{{{"test"}}} -> const B&。因此,即使声明了构造函数B(const B&),结果也与主示例相同。