不能。初始化列表中只能使用常量表达式、构造函数调用或可隐式转换的字面量/变量,禁止调用非constexpr的普通函数,因其具有运行时副作用且求值时机不满足编译期要求。

初始化列表里能直接调用普通函数吗
不能。初始化列表中每个成员的初始化表达式必须是常量表达式、构造函数调用或可隐式转换的字面量/变量,但不能出现带副作用的普通函数调用(比如 get_default_value()、compute_id() 这类非 constexpr 函数)。
编译器在初始化阶段只允许求值确定、无运行时行为的表达式;一旦你写 member_(func()),而 func() 不是 constexpr,就会报错,典型错误信息是:error: call to non-constexpr function。
- ✅ 允许:
member_(42)、member_(x)(x是参数或已声明变量)、member_(SomeClass{1,2}) - ❌ 禁止:
member_(heavy_calc())(heavy_calc非constexpr)、member_(std::rand()) - ⚠️ 特殊情况:若函数声明为
constexpr且所有参数满足常量求值条件,则可以——但这本质是编译期计算,不是“运行时调用”
为什么 consteval / constexpr 函数可以在初始化列表里用
因为它们的执行发生在编译期,结果被当作字面量嵌入初始化过程。例如:
constexpr int make_id(int base) { return base * 100 + 1; }
<p>struct S {
int id<em>;
S(int b) : id</em>(make_id(b)) {} // ✅ 合法:make_id 是 constexpr
};</p>
但如果把 make_id 改成普通函数,哪怕逻辑完全一样,也会编译失败。
- 初始化列表的求值时机早于构造函数体,甚至早于对象内存分配完成
-
constexpr函数的调用必须能在编译期完成;否则编译器拒绝它出现在初始化列表中 - 别指望用
std::string::c_str()或std::vector::size()这类运行时函数——它们永远不满足条件
想在初始化时做复杂计算,怎么办
不能硬塞进初始化列表,得绕道。常见做法是把计算逻辑封装进一个 constexpr 工具函数,或改用委托构造+局部变量缓存。
- 首选:把计算提前到参数层 —— 让调用方传入已算好的值:
S s{compute_id(x)}; - 次选:在构造函数体内用局部变量承接结果,再赋给成员(仅限非
const/非引用/有默认构造的类型):id_(0) { id_ = heavy_calc(); } - 高阶技巧:用立即调用的 lambda(需 C++17 起),但注意 lambda 本身不能捕获非 constexpr 变量:
id_(([]{ return 42; }()))
真正容易被忽略的是:即使你写了 member_(helper()) 并侥幸通过了编译,只要 helper 不是 constexpr,那它就根本没在初始化列表里执行——编译器会把它降级成构造函数体内的赋值,导致多一次默认构造+赋值,性能白亏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











