Reputation: 117
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.
Upvotes: 2
Views: 315
Reputation: 275800
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 accept
s will be routed to accept_impl
.
Code not tested or compiled, probably contains tpyos.
Upvotes: 3
Reputation: 1635
In fact you try to implement
void VisitTable<int, string>::accept(Visitor<int, string>& visitor);
with
void MyClass::accept<int, string>(Visitor<int, string>& visitor);
In C++ it is not the same method name - one has a template qualification and the other not. Moreover template
and virtual
are incompatible specifiers for methods and you should have an error for
class MyClass : ... {
...
template<typename... Types>
virtual void accept(Visitor<Types...>& visitor);
};
error: templates may not be ‘virtual’
The override
C++11 keyword helps to avoid such surprises.
Upvotes: 0