编译器默认生成的拷贝构造函数成为constexpr的规则是什么?
默认生成的拷贝/移动构造函数成为constexpr的规则
好的,咱们来聊聊C里默认生成的拷贝、移动构造函数什么时候会被编译器定义成constexpr的。其实这都是C标准明确规定的,咱们一条条拆解清楚:
核心前提:类的所有基类和非静态成员的对应构造函数必须是
constexpr
默认生成的拷贝/移动构造函数本质是对每个基类、每个非静态成员执行拷贝/移动操作。只有当这些成员和基类的拷贝/移动构造本身是constexpr时,默认构造才有可能成为constexpr。比如你提供的struct A里,成员i是const int,它的拷贝、移动操作都是constexpr,而且A没有基类,这就满足了最关键的前提。默认构造本身必须符合
constexpr函数的约束
具体要满足这些细节:- 构造函数的定义必须是
= default;(如果是= delete;那就是被删除的构造,不在讨论范围内) - 不能包含任何会导致非常量表达式的操作——因为默认拷贝/移动是逐成员/基类的操作,只要前面的前提满足,这一点自然就达成了
- 拷贝构造的参数必须是
const左值引用(默认生成的拷贝构造参数就是const A&,完全符合);移动构造的参数是右值引用,默认生成的也符合要求
- 构造函数的定义必须是
结合你给出的代码示例来看:struct A里默认生成的拷贝构造A(const A&)和移动构造A(A&&),因为所有成员的对应操作都是constexpr,所以GCC和Clang都会把它们定义为constexpr。这也是为什么你能写出constexpr A b = a;、constexpr A d{std::move(c)};这类代码——这些对象的初始化都是在编译期完成的常量表达式操作。
补充一下版本细节:从C11引入constexpr构造函数开始,这个规则就存在,后续C14、C++20对constexpr的约束有所放宽,但核心的判断逻辑始终围绕上述两点。
内容的提问来源于stack exchange,提问作者Claas Bontus
相关产品推荐
相关产品推荐

