继承模板方法

Inheriting template methods

本文关键字:模板方法 继承      更新时间:2023-10-16

我有一个类似于下面的类:

class SomeClass
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);
        //... other methods etc.
};

然而,我真正想要的是有两种不同的SomeClass。理想情况下,我将能够从通用接口派生出SomeOtherClass,但我需要doSomething的不同实现和模板方法不能是虚拟的。我可以创建一个模板化的类,但这样一来,每个采用这些方法之一(有很多)的方法本身就必须是模板等。

我能想到的最好的方法是在基类中实现两种类型的doSomething,并让该方法调用一个虚拟方法来确定在运行时使用哪个。

有更好的解决方案吗?

进一步解释

我有很多类似的方法:

void foo(SomeClass * obj);

foo调用obj->doSomething,这一切都很好,但我已经意识到,我需要一种不同的SomeClass,但希望它与这些相同的方法工作,例如:

class SomeClass
{
    public:
        // This won't work
        template<typename... Args>
        virtual void doSomething(Args && ... args) = 0;
        // ... other common methods
};
class TheFirstType
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);
        // ... other specific methods
};
class TheSecondType
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);
        // ... other specific methods
};
如果合法的话,上面的

是理想的,但是虚方法不能被模板化。到目前为止,我已经绕过了这个限制,只在基类中定义了doSomething,但TheFirstTypeTheSecondType的实现都由一个if语句分隔,该语句检查实例实际是什么类型:

template<typename... Args>
void SomeClass::doSomething(Args && ... args)
{
    if (this->type() == FIRST_TYPE) {
        // ... the implementation that should rightfully be part of TheFirstType
    } else if (this->type() == SECOND_TYPE) {
        // ... the implementation that should be part of TheSecondType
    }
}

这看起来很乱,但是,所以我想知道是否有更好的方法。

我认为@stijn的答案是正确的;你有一个理想的CRTP案例。你可以选择据此改变你的逻辑。

template<class T>
class SomeClass
{
public:
  template<typename... Args>
  void doSomething(Args && ... args)
  {
    static_cast<T*>(this)->doSomething(...);
  }
  //other method can be virtual
  virtual void foo ()
  {
    doSomething(...);
    // ... other code;
  }
};

现在只需将这些class继承到您的其他子类:

class TheFirstType : SomeClass<TheFirstType>
{
public:
  template<typename... Args>
  void doSomething(Args && ... args) { ... }
  virtual void foo ()
  {
  }
};   // do same for TheSecondType.

我猜你是在CRTP之后(尽管我不能确定,正如iammilind在评论中指出的那样):

template< class Parent >
class SomeClassBase : public Parent
{
public:
  //common methods go here
};
class SomeClass : public SomeClassBase< SomeClass >
{
public:
  template<typename... Args>
  void doSomething(Args && ... args);
};
class SomeOtherClass : public SomeClassBase< SomeOtherClass >
{
public:
  template<typename... Args>
  void doSomething(Args && ... args);
};

在这种情况下可能有用的是在包装器类SomeClass中使用宏函数。宏的好处是文本替换。通常情况下,我们不能在c++中将函数的所有参数都作为对象传递(至少在c++ 11之前,我不确定)。然而,使用宏,我们可以传递几乎任何类型的文本。这里的额外好处是,它将为每个具有此模板虚拟冲突的函数删除if/else的重复代码。

我们可以这样设置宏:

#define CLASS_SELECT(func) 
do { 
    if (this->type() == FIRST_TYPE) { 
        theFirstType.func; 
    } else if (this->type() == SECOND_TYPE) { 
        theSecondType.func; 
    } 
} while (0)

如果您不熟悉do while封装,请查看这里。该类将使用如下宏:

class SomeClass
{
    TheFirstType theFirstType;
    TheSecondType theSecondType;
public:
    template<typename... Args>
    void doSomething(Args && ... args)
    {
        CLASS_SELECT(doSomething (&args...) );
    }
};

在上面的例子中,我实例化了SomeClass内部的专门化对象。我不确定这是否是您喜欢的设计,如果不是,我会考虑在宏中使用静态getter函数或类似的函数。

无论如何,我承认我的解决方案可能不是理想的,但它是最好的我有到目前为止(我有同样的问题,你在我的代码)。我承认在其他答案中引用的CRTP非常酷,尽管它不适合我的需要(必须在参数中指定模板也不适合我,特别是在运行时)。