子类调用模板化静态方法时自动推导类类型的实现方案
实现静态
create()自动识别调用类的解决方案 你提到的这个场景确实很常见——希望父类的静态模板方法能自动感知调用它的子类类型,不用每次都显式指定模板参数,也不用每个子类都重复写create()方法。遗憾的是C++里并没有this_type这种魔法关键字,但我们有两种靠谱的方式实现这个需求:
方法一:利用CRTP(奇异递归模板模式)
这是最常用的解决方案,通过让子类继承父类时传入自身类型,父类就能拿到子类的类型信息:
template <typename Derived> struct FooBase { static Derived* create() { return new Derived(); } }; // 子类继承时传入自身作为模板参数 struct Foo : FooBase<Foo> {}; struct Bar : FooBase<Bar> {}; struct Baz : FooBase<Baz> {}; int main() { Foo::create(); // 创建Foo对象 Bar::create(); // 直接创建Bar对象,无需显式指定模板参数 Baz::create(); // 同理创建Baz对象 return 0; }
原理说明
CRTP通过把子类类型注入到父类模板中,让父类的静态方法直接使用Derived类型来创建对象,完美解决了自动识别调用类的问题。而且每个子类只需要在继承时多写一个模板参数,不用额外实现create()方法,哪怕有成千上万个子类也能轻松维护。
方法二:利用C++11的decltype和成员函数推导(不推荐,但可行)
如果你不想用CRTP,还有一种方式是把静态方法改成非静态的,然后通过decltype推导调用者的类型,但这种方式需要先创建临时对象(或者用std::declval),实用性不如CRTP:
#include <type_traits> struct Foo { template <typename T = decltype(*this)> static T* create() { return new T(); } }; struct Bar : Foo {}; struct Baz : Foo {}; int main() { Foo::create(); // 创建Foo // 需显式指定或借助临时对象,写法繁琐 Bar{}.create<Bar>(); std::remove_reference_t<decltype(std::declval<Bar>())>::create(); return 0; }
这种方式显然不够优雅,要么需要创建临时对象,要么写法非常繁琐,远不如CRTP简洁实用。
为什么原代码里Bar::create()会创建Foo?
你原代码里Bar::create()没有指定模板参数时,会使用父类Foo中定义的默认模板参数T = Foo——子类继承静态方法时并不会修改这个默认值,所以才会出现调用Bar::create()却创建Foo对象的混淆情况。
总结下来,CRTP是解决这个问题的最优方案,它既满足了自动识别调用类的需求,又不需要子类额外编写重复代码,完全符合你的要求。
内容的提问来源于stack exchange,提问作者Vortico
相关产品推荐
相关产品推荐

