I have the following classes:
enum class Group
{
A,
B
};
template <Group G>
class AbstractGroupVisitor;
template <Group G>
class GroupMessage;
class AbstractMessageVisitor;
class AbstractMessage
{
public:
virtual void accept(AbstractMessageVisitor& visitor) = 0;
};
class AbstractMessageVisitor
{
public:
virtual void visit(GroupMessage<Group::A>& msg) = 0;
virtual void visit(GroupMessage<Group::B>& msg) = 0;
//A pure virtual method for each item in the Group enum
};
template <Group G>
class GroupMessage:
public AbstractMessage
{
public:
void accept(AbstractMessageVisitor& visitor) final { visitor.visit(*this); }
virtual void accept(AbstractGroupVisitor<G>& visitor) = 0;
};
Is there a way I can write a CRTP template like the following
template <Group... Gs>
class GroupsVisitor;
That would be able to:
- Inherit from
AbstractMessageVisitor
- Inherit from
AbstractGroupVisitor
for every Group inGs
- Implement the
visit
method fromAbstractMessageVisitor
for every Group inGs
If I were to write a class manually, it would look like:
class MyVisitor:
public AbstractMessageVisitor,
public AbstractGroupVisitor<Group::A>,
public AbstractGroupVisitor<Group::B>
{
public:
void visit(GroupMessage<Group::A>& msg) final { msg.accept(static_cast<AbstractGroupVisitor<Group::A>&>(*this)); }
void visit(GroupMessage<Group::B>& msg) final { msg.accept(static_cast<AbstractGroupVisitor<Group::B>&>(*this)); }
};
As a side note, I am doing this in order to mimic some of the features of virtual inheritance without the overhead of thunks and excess tables for every method in the final class.
CodePudding user response:
You could do some recursion based on template specialization of GroupsVisitor
. The following code compiles for me:
template <Group... Gs>
class GroupsVisitor;
template <>
class GroupsVisitor<> : public AbstractMessageVisitor {};
template <Group First, Group ... Rest>
class GroupsVisitor<First, Rest...> : public AbstractGroupVisitor<First>, public GroupsVisitor<Rest...> {
public:
void visit(GroupMessage<First>& msg) final {
msg.accept(static_cast<AbstractGroupVisitor<First>&>(*this));
}
};
class MyVisitor : public GroupsVisitor<Group::A, Group::B> {
};
MyVisitor myVisitor;
but I had to change AbstractGroupVisitor
from being forward declared to have a class body:
template <Group G>
class AbstractGroupVisitor {};
Otherwise, the compiler complains about "incomplete type".