空初始化列表作参数未调用默认构造函数的原因解析
关于C++列表初始化中的构造函数调用逻辑
咱们一步一步拆解你遇到的这几个场景,搞清楚编译器到底在做什么:
1. 存在A(int i)构造时,A obj({})调用单参数构造的原因
当你写A obj({})时,这属于直接列表初始化。编译器会优先寻找能匹配初始化列表的构造函数,但咱们的类A并没有定义std::initializer_list参数的构造函数,所以编译器会退而求其次,尝试把初始化列表里的内容当作单个参数来匹配构造函数。
空的初始化列表{}可以触发值初始化,对于int类型来说,值初始化的结果就是0。所以这里的{}会被隐式转换为int(0),刚好匹配到A(int i)这个构造函数,于是就调用它了。
2. 移除A(int i)后,A obj({})调用默认构造的原因
当没有单参数的int构造函数时,编译器再次检查有没有能匹配初始化列表的构造函数(还是没有initializer_list构造)。这时候根据C++的规则,如果列表初始化时传入的是空列表,且没有对应的构造函数可以匹配,那么编译器会直接调用类的默认构造函数——相当于把A obj({})等价于A obj;来处理。
3. 为什么A obj{{}}总是调用单参数构造函数
这里的{{}}是嵌套的初始化列表,外层的{}是用来初始化对象的列表,内层的{}则被当作一个单独的参数传递给构造函数。不管内层列表是空还是有内容,编译器都会把它当作单个参数来匹配。
对于A(int i)构造来说,内层的{}同样会触发int的值初始化(变成0),所以会成功匹配单参数构造函数。哪怕你把内层列表换成{5},也会直接把5传给int参数,逻辑是一致的。
简单总结一下:
A obj({})的行为取决于有没有能接收单个可被空列表初始化的参数的构造函数:有就调用它,没有就走默认构造。A obj{{}}则明确把内层列表当作单个参数,所以只要存在对应的单参数构造(比如A(int)),就会优先调用它。
内容的提问来源于stack exchange,提问作者sanjivgupta
相关产品推荐
相关产品推荐

