How to achieve "virtual template function" in C++

Solution 1:

After some thinking I recognized this as the classic multi-method requirement, i.e. a method that dispatches based on the runtime type of more than one parameter. Usual virtual functions are single dispatch in comparison (and they dispatch on the type of this only).

Refer to the following:

  • Andrei Alexandrescu has written (the seminal bits for C++?) on implementing multi-methods using generics in 'Modern C++ design'
    • Chapter 11: "Multimethods" - it implements basic multi-methods, making them logarithmic (using ordered typelists) and then going all the way to constant-time multi-methods. Quite powerful stuff !
  • A codeproject article that seems to have just such an implementation:
    • no use of type casts of any kind (dynamic, static, reinterpret, const or C-style)
    • no use of RTTI;
    • no use of preprocessor;
    • strong type safety;
    • separate compilation;
    • constant time of multimethod execution;
    • no dynamic memory allocation (via new or malloc) during multimethod call;
    • no use of nonstandard libraries;
    • only standard C++ features is used.
  • C++ Open Method Compiler, Peter Pirkelbauer, Yuriy Solodkyy, and Bjarne Stroustrup
  • The Loki Library has A MultipleDispatcher
  • Wikipedia has quite a nice simple write-up with examples on Multiple Dispatch in C++.

Here is the 'simple' approach from the wikipedia article for reference (the less simple approach scales better for larger number of derived types):

// Example using run time type comparison via dynamic_cast

struct Thing {
    virtual void collideWith(Thing& other) = 0;
}

struct Asteroid : Thing {
    void collideWith(Thing& other) {
        // dynamic_cast to a pointer type returns NULL if the cast fails
        // (dynamic_cast to a reference type would throw an exception on failure)
        if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
            // handle Asteroid-Asteroid collision
        } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
            // handle Asteroid-Spaceship collision
        } else {
            // default collision handling here
        }
    }
}

struct Spaceship : Thing {
    void collideWith(Thing& other) {
        if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
            // handle Spaceship-Asteroid collision
        } else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
            // handle Spaceship-Spaceship collision
        } else {
            // default collision handling here
        }
    }
}

Solution 2:

Obviously, virtual member function templates are not allowed and could not be realized even theoretically. To build a base class' virtual table, there needs to be a finite number of virtual function-pointer entries. A function template would admit an indefinite amount of "overloads" (i.e. instantiations).

Theoretically-speaking, a language (like C++) could allow virtual member function templates if it had some mechanism to specify the actual (finite) list of instantiations. C++ does have that mechanism (i.e. explicit template instantiations), so I guess it could be possible to do this in a newer C++ standard (although I have no idea what trouble it would entail for compiler vendors to implement this feature). But, that's just a theoretical discussion, in practice, this is simply not allowed. The fact remains, you have to make the number of virtual functions finite (no templates allowed).

Of course, that doesn't mean that class template cannot have virtual functions, nor does it mean that virtual functions cannot call function templates. So, there are many solutions in that vein (like the Visitor pattern or other schemes).

One solution that, I think, serves your purpose (although it is hard to comprehend) elegantly is the following (which is basically a visitor pattern):

#include <iostream>
#include <vector>

struct Eater { 
  virtual void operator()(int amount) const = 0;
  virtual void operator()(double amount) const = 0;
};

template <typename EaterType>
struct Eater_impl : Eater {
  EaterType& data;
  Eater_impl(EaterType& aData) : data(aData) { };
  virtual void operator()(int amount) const { data.eat_impl(amount); };
  virtual void operator()(double amount) const { data.eat_impl(amount); };
};

class Animal {
  protected:
    Animal(Eater& aEat) : eat(aEat) { };
  public:
    Eater& eat;
    virtual ~Animal() { delete &eat; };
};

class Wolf : public Animal {
  private:
    template< class AMOUNT >
    void eat_impl( AMOUNT amount) const { 
      std::cout << "I eat like a wolf!" << std::endl; 
    }

  public:
    friend struct Eater_impl<Wolf>;        
    Wolf() : Animal(*(new Eater_impl<Wolf>(*this))) { };
    virtual ~Wolf() { };
};

class Fish : public Animal {
  private:
    template< class AMOUNT >
    void eat_impl( AMOUNT amount) const { 
      std::cout << "I eat like a fish!" << std::endl; 
    }
  public:
    friend struct Eater_impl<Fish>;
    Fish() : Animal(*(new Eater_impl<Fish>(*this))) { };
    virtual ~Fish() { };
};

int main() {
  std::vector<Animal*> animals;
  animals.push_back(new Wolf());
  animals.push_back(new Fish());

  for (std::vector<Animal*>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
    (*it)->eat(int(0));
    (*it)->eat(double(0.0));
    delete *it;
  };

  return 0;
};

The above is a neat solution because it allows you to define a finite number of overloads that you want in one place only (in the Eater_impl class template) and all you need in the derived class is a function template (and possibly additional overloads, for special cases). There is, of course, a bit of overhead, but I guess that a bit more thought could be put into it to reduce the overhead (additional reference storage and dynamic allocation of Eater_impl). I guess, the curiously recurring template pattern could probably be employed somehow to this end.

Solution 3:

I think the visitor pattern can be a solution.

UPDATE

I finished my example:

#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>

class Animal;
class Wolf;
class Fish;

class Visitor
{
    public:
    virtual void visit(const Animal& p_animal) const = 0;
    virtual void visit(const Wolf& p_animal) const = 0;
    virtual void visit(const Fish& p_animal) const = 0;
};

template<class AMOUNT>
class AmountVisitor : public Visitor
{
    public:
    AmountVisitor(AMOUNT p_amount) : m_amount(p_amount) {}
    virtual void visit(const Animal& p_animal) const
    {
        std::cout << "I eat like a generic Animal." << std::endl;
    }
    virtual void visit(const Wolf& p_animal) const
    {
        std::cout << "I eat like a wolf!" << std::endl;
    }
    virtual void visit(const Fish& p_animal) const
    {
        std::cout << "I eat like a fish!" << std::endl;
    }


    AMOUNT m_amount;
};

class Animal {
    public:

        virtual void Accept(const Visitor& p_visitor) const
        {
            p_visitor.visit(*this);
        }

        virtual ~Animal() {
        }
};

class Wolf : public Animal {
    public:
        virtual void Accept(const Visitor& p_visitor) const
        {
            p_visitor.visit(*this);
        }
};

class Fish : public Animal {
    public:
        virtual void Accept(const Visitor& p_visitor) const
        {
            p_visitor.visit(*this);
        }
};

int main()
{
    typedef boost::shared_ptr<Animal> TAnimal;
    std::vector<TAnimal> animals;
    animals.push_back(TAnimal(new Animal()));
    animals.push_back(TAnimal(new Wolf()));
    animals.push_back(TAnimal(new Fish()));

    AmountVisitor<int> amount(10);

    for (std::vector<TAnimal>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
        (*it)->Accept(amount);
    }

    return 0;
}

this prints:

I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!

Solution 4:

Per Mikael's post, I have made another offshoot, using the CRTP and following Eigen's style of using derived() for an explicit subclass reference:

// Adaptation of Visitor Pattern / CRTP from:
// http://stackoverflow.com/a/5872633/170413

#include <iostream>
using std::cout;
using std::endl;

class Base {
public:
  virtual void tpl(int x) = 0;
  virtual void tpl(double x) = 0;
};

// Generics for display
template<typename T>
struct trait {
  static inline const char* name() { return "T"; }
};
template<>
struct trait<int> {
  static inline const char* name() { return "int"; }
};
template<>
struct trait<double> {
  static inline const char* name() { return "double"; }
};

// Use CRTP for dispatch
// Also specify base type to allow for multiple generations
template<typename BaseType, typename DerivedType>
class BaseImpl : public BaseType {
public:
  void tpl(int x) override {
    derived()->tpl_impl(x);
  }
  void tpl(double x) override {
    derived()->tpl_impl(x);
  }
private:
  // Eigen-style
  inline DerivedType* derived() {
    return static_cast<DerivedType*>(this);
  }
  inline const DerivedType* derived() const {
    return static_cast<const DerivedType*>(this);
  }
};

// Have Child extend indirectly from Base
class Child : public BaseImpl<Base, Child> {
protected:
  friend class BaseImpl<Base, Child>;
  template<typename T>
  void tpl_impl(T x) {
    cout << "Child::tpl_impl<" << trait<T>::name() << ">(" << x << ")" << endl;
  }
};

// Have SubChild extend indirectly from Child
class SubChild : public BaseImpl<Child, SubChild> {
protected:
  friend class BaseImpl<Child, SubChild>;
  template<typename T>
  void tpl_impl(T x) {
    cout << "SubChild::tpl_impl<" << trait<T>::name() << ">(" << x << ")" << endl;
  }
};


template<typename BaseType>
void example(BaseType *p) {
  p->tpl(2);
  p->tpl(3.0);
}

int main() {
  Child c;
  SubChild sc;

  // Polymorphism works for Base as base type
  example<Base>(&c);
  example<Base>(&sc);
  // Polymorphism works for Child as base type
  example<Child>(&sc);
  return 0;
}

Output:

Child::tpl_impl<int>(2)
Child::tpl_impl<double>(3)
SubChild::tpl_impl<int>(2)
SubChild::tpl_impl<double>(3)
SubChild::tpl_impl<int>(2)
SubChild::tpl_impl<double>(3)

This snippet may be found in source here: repro:c808ef0:cpp_quick/virtual_template.cc

Solution 5:

Virtual template function is not allowed. However you can use one OR the other here.

You could make an interface using virtual methods and implement your various animals in terms of having an eating interface. (i.e. PIMPL)

Less human intuitive would be having a non-member non-friend template function as a free function which could take templated const reference to any animal and make them eat accordingly.

For the record you don't need templates here. Pure virtual abstract method on the base class is enough to force and interface where all animals must eat and define how they do so with an override, providing a regular virtual would be enough to say all animals can eat but if they don't have a specific way then they can use this default way.