Milleras Milleras - 13 days ago 5
C++ Question

C++: Overriding virtual pure function derived from a template class

I wrote some classes based on this excellent visitor pattern described here (my implementation is a little bit different).

template<typename... Types>
class Visitable {
public:
virtual void accept(Visitor<Types...>& visitor) = 0;
};

class MyClass : public Visitable<int, string>
{
virtual void accept(Visitor<int, string>& visitor)
{
/*** my code ***/
}
};


This code above works but I would like implement
MyClass
like that:

class MyClass : public Visitable<int, string>
{
template<typename... Types>
virtual void accept(Visitor<Types...>& visitor)
{
/*** my code ***/
}
};


Obviously I changed the call to the accept method but I have this error: "cannot instantiate abstract class". Why in this second case,
accept()
is not overridden ? MyClass should be templated ?

Thanks.

Answer

Use the CRTP:

template<class D, class...Ts>
struct Visitable_CRTP : public Visitable<Ts...> {
  virtual void accept(Visitor<Ts...>& visitor) override final {
    return static_cast<D*>(this)->accept_impl(visitor);
  }
};
class MyClass : public Visitable_CRTP<MyClass, int, string>
{
  template<typename... Types>
  void accept_impl(Visitor<Types...>& visitor) // not virtual
  {
          /*** my code ***/
  }
};

Visitor_CRTP writes the glue code that attaches virtual accept to your template accept_impl.

If you want to have more than one accept method, we can do this:

template<class D, class...Visitables>
struct PolyVisitable_CRTP {};

template<class D, class...V0, class...Vs>
struct PolyVisitable_CRTP<D, Visitable<V0...>, Vs...>
  Visitable_CRTP<D, V0...>,
  PolyVisitable_CRTP<D, Vs...>
{};

which can be used like this:

class MyClass :
  public PolyVisitable_CRTP<MyClass,
    Visitable<int,double>,
    Visitable<std::string, char, wchar_t>,
    Visitable<>
  >
{
  template<typename... Types>
  void accept_impl(Visitor<Types...>& visitor)
  {
          /*** my code ***/
  }
};

and all of the Visitable bases's accepts will be routed to accept_impl.

Code not tested or compiled, probably contains tpyos.

Comments