Home > Enterprise >  Override method for each in parameter pack
Override method for each in parameter pack

Time:11-30

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:

  1. Inherit from AbstractMessageVisitor
  2. Inherit from AbstractGroupVisitor for every Group in Gs
  3. Implement the visit method from AbstractMessageVisitor for every Group in Gs

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".

  • Related