如何实现无需显式指定模板参数调用MyClass::Create()?
解决Disposable基类Create方法的模板参数推导问题
现有基类Disposable和派生类MyClass的实现如下:
class Disposable : public PolymorphicE { protected: virtual void Created() {} virtual void Disposing() {} public: template <typename DisposableClass, typename ... Args> static DisposableClass* Create(Args&& ... constructorArgs) { DisposableClass* result = new DisposableClass(std::forward<Args>(constructorArgs)...); result->Created(); return result; } void Dispose() { Disposing(); delete this; } }; class MyClass : public Disposable { public: MyClass(int param1, double param2) {} };
当前创建对象需要写MyClass::Create<MyClass>(45, 23.74);,希望简化为MyClass::Create(45, 23.74);,由于无法通过::左侧的类名推导模板参数,以下是几种可行的实现方式:
方案一:使用CRTP(奇异递归模板模式)
让基类通过模板参数获取派生类的类型,这样Create函数就不需要额外指定模板参数了:
template <typename Derived> class Disposable : public PolymorphicE { protected: virtual void Created() {} virtual void Disposing() {} public: template <typename ... Args> static Derived* Create(Args&& ... constructorArgs) { Derived* result = new Derived(std::forward<Args>(constructorArgs)...); result->Created(); return result; } void Dispose() { Disposing(); delete this; } }; // 派生类继承时传入自身作为模板参数 class MyClass : public Disposable<MyClass> { public: MyClass(int param1, double param2) {} };
现在就可以直接通过MyClass::Create(45, 23.74);创建对象,基类已经通过CRTP明确要实例化的派生类类型。
方案二:在派生类中添加转发函数
在MyClass里定义一个静态的Create函数,内部调用基类的Create<MyClass>,对外隐藏模板参数:
class Disposable : public PolymorphicE { protected: virtual void Created() {} virtual void Disposing() {} public: template <typename DisposableClass, typename ... Args> static DisposableClass* Create(Args&& ... constructorArgs) { DisposableClass* result = new DisposableClass(std::forward<Args>(constructorArgs)...); result->Created(); return result; } void Dispose() { Disposing(); delete this; } }; class MyClass : public Disposable { public: MyClass(int param1, double param2) {} // 派生类的转发函数,自动推导参数并转发给基类 template <typename ... Args> static MyClass* Create(Args&& ... args) { return Disposable::Create<MyClass>(std::forward<Args>(args)...); } };
这种方式不需要修改基类,只需要在每个派生类中添加对应的转发函数,同样可以用MyClass::Create(45, 23.74);创建对象。
方案三:C++23显式对象参数
如果你的编译器支持C++23标准,可以使用显式对象参数(this参数)来让模板参数推导生效。修改基类的Create函数为带显式对象参数的静态函数,通过调用时的类类型推导模板参数:
class Disposable : public PolymorphicE { protected: virtual void Created() {} virtual void Disposing() {} public: template <typename Derived, typename ... Args> static Derived* Create(this Derived*, Args&& ... constructorArgs) { Derived* result = new Derived(std::forward<Args>(constructorArgs)...); result->Created(); return result; } void Dispose() { Disposing(); delete this; } }; class MyClass : public Disposable { public: MyClass(int param1, double param2) {} };
现在可以直接通过MyClass::Create(45, 23.74);调用,编译器会根据MyClass的类型自动推导Derived模板参数。注意这种方式依赖C++23的特性,需要确认编译器版本支持。
内容的提问来源于stack exchange,提问作者Ibrahim Ozdemir
相关产品推荐
相关产品推荐

