为何模板constexpr/inline/consteval函数声明实现分离搭配显式实例化可正常运行?
问题解答
核心原理
你印象中「模板、constexpr、inline甚至consteval函数的实现必须对编译器可见」的结论,仅适用于两种场景:
- 模板需要隐式实例化的场景
- 要求
constexpr/consteval函数在编译期常量上下文求值的场景
其中*consteval修饰的函数是唯一例外*:它强制所有调用必须在编译期完成,因此实现必须对调用处的编译器可见,哪怕做了显式实例化也无法通过运行时链接调用。
你的代码可以正常运行的原因
你的代码刚好避开了上述需要实现可见的场景:
- 你在
vector3.cpp中对用到的模板类型做了显式实例化:- 显式实例化了
Vector3<double>类模板,因此Vector3<double>的构造函数、operator+的double版本都会被编译为实体,保存在vector3.cpp对应的目标文件中 - 显式实例化了
dot<double>函数模板,对应的函数实体也被编译完成
- 显式实例化了
- 你没有要求这些
constexpr函数在编译期常量上下文求值:main函数中的result没有被constexpr修饰,因此所有函数调用都走运行时路径,链接器可以正常找到显式实例化生成的符号,不会报错。
会触发你预期错误的场景
只要满足任意一个条件,你就会得到预想中的编译/链接错误:
- 强制编译期求值:将main中的代码修改为
constexpr double result {dot(i + j, j)};,此时编译器必须在编译期计算result的值,但无法看到dot和operator+的实现,会直接编译报错。 - 删除显式实例化代码:删掉
vector3.cpp末尾的4行显式实例化代码,此时模板没有生成对应的double版本实体,链接器会直接报找不到operator+和dot符号的错误。
关于inline修饰符的补充
inline只是编译器的优化提示,同时允许函数在多个翻译单元重复定义,只要显式实例化生成了对应的函数实体,链接阶段就可以正常找到,不会因为实现不在头文件就报错。
内容的提问来源于stack exchange,提问作者Nima Ghorab
相关产品推荐
相关产品推荐

