C++中仅含带默认参数拷贝构造函数的类是否为LiteralType
C++字面类型与带默认参数的拷贝构造函数问题解答
结论先行
GCC和Clang的实现符合C++标准要求,MSVC的处理存在偏差。
核心规则依据
首先明确两个标准定义:
类T的拷贝构造函数是一类非模板构造函数,其首个参数为T&、const T&、volatile T&或const volatile T&,且要么无其他参数,要么其余所有参数都有默认值。
非聚合类的字面类型要求:该类型至少拥有一个非拷贝或移动构造函数的constexpr(可以是模板)构造函数。
规则推演
- 带默认额外参数的拷贝构造函数,本质仍属于拷贝构造函数:
只要构造函数满足拷贝构造的定义特征,不管调用时是否传入了额外参数,它的身份始终是拷贝构造函数,不会因为调用方式的变化变成普通构造函数。 - 对示例中两个类的分析:
- 类
A的第二个构造函数constexpr A(const A &, int)没有给第二个参数设置默认值,不满足拷贝构造“其余所有参数都有默认值”的要求,因此它属于普通constexpr构造函数,符合字面类型的要求,所以代码可以正常编译。 - 类
B唯一的构造函数constexpr B(const B &, int = 0)完全符合拷贝构造函数的定义,属于拷贝构造函数,没有其他非拷贝/移动的constexpr构造函数,因此B不属于字面类型,不能定义constexpr修饰的B类型变量,GCC和Clang的报错符合标准要求。
关于MSVC的差异
MSVC错误地将“调用带默认额外参数的拷贝构造函数时传入额外参数”的场景,判定为调用普通构造函数,忽略了该构造函数本身的拷贝构造身份,不符合标准规定。
// 示例代码回顾 struct A { constexpr A(const A &) {} constexpr A(const A &, int) {} }; constexpr A a{ a, 1 }; // 符合标准,编译通过 struct B { constexpr B(const B &, int = 0) {} }; constexpr B b{ b, 1 }; // 不符合标准,GCC/Clang报错,MSVC错误接受
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

