Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheriting template methods

I have a class similar to the following:

class SomeClass
{
    public:
        template<typename... Args>
        void doSomething(Args && ... args);

        //... other methods etc.
};

However, what I really want is to have two different kinds of SomeClass. Ideally, I would be able to derive from a common interface to make SomeOtherClass, but I need to have a different implementation of doSomething and templated methods cannot be virtual. I could make a templated class, but then every method that takes one of these (and there are many) would themselves have to be templates etc.

The best I've been able to come up with is to implement both types of doSomething in the base class and have that method call a virtual method to determine which to use at runtime.

Is there a better solution?

Further explanation

I have many methods that look similar to this:

void foo(SomeClass * obj);

foo calls obj->doSomething and this all works fine, however I've since realized that I need a different kind of SomeClass but want it to work with these same methods, for example:

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
};

The above would be ideal, if it were legal, but virtual methods cannot be templated. I've thus far gotten around this limitation by only having doSomething defined in the base class, but with both the implementation for TheFirstType and TheSecondType separated by an if statement that checks on what type the instance actually is:

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
    }
}

This seems messy, however, so I was wondering if there is a better way.

like image 200
Sydius Avatar asked Jul 15 '11 05:07

Sydius


People also ask

Can template functions be inherited?

It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

What is template inheritance?

Template inheritance allows you to build a base “skeleton” template that contains all the common elements of your site and defines blocks that child templates can override. Sounds complicated but is very basic. It's easiest to understand it by starting with an example.

Is inheritance better than templates?

Inheritance provides runtime abstraction. Templates are code generation tools. Because the concepts are orthogonal, they may happily be used together to work towards a common goal.

What is C++ template method?

Template Method in C++ Template Method is a behavioral design pattern that allows you to defines a skeleton of an algorithm in a base class and let subclasses override the steps without changing the overall algorithm's structure.


2 Answers

I think @stijn's answer is correct; you have an ideal case for CRTP. You may choose to alter your logic according to that.

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;
  }
};

Now simply inherit these class to your other child classes:

class TheFirstType : SomeClass<TheFirstType>
{
public:
  template<typename... Args>
  void doSomething(Args && ... args) { ... }

  virtual void foo ()
  {
  }
};   // do same for TheSecondType.

You are done.

like image 121
iammilind Avatar answered Sep 19 '22 13:09

iammilind


my guess is that you're after CRTP (although I can't be sure, as iammilind points out in the comment):

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);
};
like image 26
stijn Avatar answered Sep 21 '22 13:09

stijn