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.
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.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments