constexpr构造函数需通过编译器静态审查,任一非常量表达式或非字面类型成员均使其静默退化为普通构造函数,导致编译期特性失效。

constexpr 构造函数不是加个关键字就生效
它本质是编译器对整个构造过程的“静态审查”——只要有一处无法在编译期求值,constexpr 就会静默失效(变成普通构造函数),而不会报错。你可能以为对象是编译期创建的,实际却在运行时才构造,这会导致 static_assert 失败、模板参数不合法、数组大小非字面量等连锁问题。
所有成员初始化必须写在初始化列表里
构造函数体内部不能做任何初始化操作;所有成员必须通过初始化列表用常量表达式完成赋值。哪怕只漏一个成员、或用默认成员初始化器(= 0)但该初始化器本身不是常量表达式,整个构造函数就失去 constexpr 资格。
-
x_(x)合法,前提是x是字面类型且传入的是常量表达式(如字面量、constexpr变量) -
x_(std::max(1, x))在 C++14+ 中可能合法,但要求std::max是constexpr版本(C++20 起标准库多数算法才支持) -
x_(some_runtime_func())直接非法,编译失败 - 类中含
std::string、std::vector等非字面类型成员 → 整个类无法拥有constexpr构造函数
C++ 标准版本决定你能写多复杂的逻辑
不同标准对函数体的容忍度差异极大,不是“写了就能用”,得看编译器按哪个标准解析:
- C++11:函数体必须为空或仅含
return;;连局部变量都不允许 - C++14:允许局部变量、
if、for、简单赋值,但所有操作仍须是常量表达式(比如int i = 0; while (i 合法,前提是 <code>n是编译期常量) - C++20:支持有限制的
try/catch、dynamic_cast、甚至new(需配合consteval或特定上下文),但日常极少需要,且主流编译器支持尚不稳定
类本身必须是字面类型(LiteralType)
这是容易被忽略的底层前提。类要成为字面类型,必须同时满足:
立即学习“C++免费学习笔记(深入)”;
- 析构函数是平凡的(
~T() = default)或constexpr - 所有非静态成员和基类都是字面类型
- 不能有虚函数、虚基类、用户定义的拷贝/移动操作(除非是
constexpr且平凡) - 构造函数(至少一个)是
constexpr的
例如,哪怕你把 constexpr 写对了,但类里加了一行 virtual void foo() = 0;,这个类立刻失去字面类型资格,constexpr 构造函数也就没意义了。


















