You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现无需显式指定模板参数调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 21:23:12