CRTP是一种通过派生类继承自身为模板参数的基类实现静态多态的C++惯用法,用于替代虚函数以获得零开销抽象、编译期绑定及派生类静态信息访问。

CRTP(Curiously Recurring Template Pattern),中文常译作“奇异递归模板模式”,是 C++ 中一种借助模板和继承实现静态多态的惯用法。它的核心特点是:派生类以自身作为模板参数,继承自一个以该派生类为模板实参的基类。
CRTP 的基本写法
典型结构如下:
templateclass Base { public: void interface() { static_cast (this)->implementation(); // 向下调用派生类函数 } }; class MyDerived : public Base { public: void implementation() { // 具体逻辑 } };
这里 MyDerived 继承自 Base,而 Base 又通过 static_cast 安全地调用派生类成员——这种“递归式”模板参数就是“奇异”的来源。
CRTP 解决什么问题
它主要替代虚函数机制,在编译期绑定调用,避免运行时开销和虚表间接访问。适用于:
立即学习“C++免费学习笔记(深入)”;
- 需要零成本抽象的场景(如 Eigen、Boost.TypeErasure 内部)
- 实现通用接口但拒绝虚函数(嵌入式、高性能计算)
- 在基类中获取派生类的静态信息(如
sizeof(Derived)、类型别名、编译期常量) - 模拟 final 类行为或强制实现某些接口(配合
static_assert)
常见进阶用法
CRTP 不只是简单转发调用,还能支撑更复杂的泛型设施:
- 混入(Mixin)编程:多个 CRTP 基类组合,为派生类注入不同能力(如日志、序列化、计数)
-
静态多态容器:基类模板可定义统一接口(如
clone()),各派生类提供static版本,无需虚析构 -
编译期反射辅助:结合
constexpr和类型特征,在基类中推导派生类字段布局(需 C++20 支持更多元的模板元编程) -
安全的 downcast 封装:基类提供
self()成员函数,返回static_cast,避免重复书写 cast(*this)
注意点和陷阱
CRTP 看似简洁,但使用时需谨慎:
- 派生类必须在定义完成后才实例化基类模板,否则
Derived是不完整类型,无法在基类中使用其成员(除指针/引用外) - 不能直接用于多继承中的“菱形继承”,容易引发二义性;若需组合多个 CRTP 行为,应让它们都继承自同一空基类或采用策略类方式
- 调试时堆栈可能略显晦涩(模板展开深、符号名长),建议配合
[[nodiscard]]和清晰命名提升可读性 - 不支持动态对象创建(如
new Base),所有实例必须是具体派生类型











