带转换构造函数的类型拷贝初始化失效但列表初始化有效?C++新版本是否仍如此?
问题解析:为什么
B b1 = 5;会报错? 先看你给出的代码:
// C++ 14. struct A { A(int i) {} }; struct B { B(A a) {} }; int main(){ A a = 5; B b1 = 5; // error B b2 = a; B b3 { 5 }; B b4 = { 5 }; return 0; }
报错核心原因:拷贝初始化的隐式转换限制
你观察的结论是对的,拷贝初始化(T obj = expr;形式)仅允许最多一层用户定义的隐式转换。B b1 = 5;需要两层用户定义转换才能完成:
- 第一步:
int类型的5通过A的构造函数隐式转换为A对象(第一层用户定义转换); - 第二步:
A对象通过B的构造函数隐式转换为B对象(第二层用户定义转换)。
C++标准明确规定,隐式转换序列中最多只能包含一次用户定义的转换(包括构造函数转换或转换函数),因此这条语句违反规则,编译器会报错。
其他初始化语句的合法性说明:
A a = 5;:仅需一层用户定义转换(int→A),符合拷贝初始化规则;B b2 = a;:仅需一层用户定义转换(A→B),符合拷贝初始化规则;B b3 { 5 };和B b4 = { 5 };:属于直接初始化/列表初始化,这类初始化会直接尝试用5作为参数调用B的构造函数,此时仅需将5转换为B构造函数要求的A类型(一层用户定义转换),因此可以正常编译。
最新C++版本中的行为
这个规则在C17、C20乃至C++23中依然存在,拷贝初始化的隐式转换序列限制未被修改。只要代码结构不变,B b1 = 5;在最新标准中仍会触发编译错误。
内容的提问来源于stack exchange,提问作者TSs
相关产品推荐
相关产品推荐

