Implications of using mpl::inherit_linearly for defining interfaces
Asked Answered
P

1

8

I am writing some message handling code, whereby each message is a POD structure. On way of writing this would be to define an abstract base class, with virtual functiosn for each message type e.g:

class AbstractHandler
{
public:
    virtual void handleMessage( const MessageType1& msg ) =0;
    virtual void handleMessage( const MessageType2& msg ) =0;
    virtual void handleMessage( const MessageType3& msg ) =0;
    virtual void handleMessage( const MessageType4& msg ) =0;
};

And then create derived concrete classes that implement the handler functions:

class ConcreteHandler : public AbstractHandler
{
public:
    virtual void handleMessage( const MessageType1& msg );
    virtual void handleMessage( const MessageType2& msg );
    virtual void handleMessage( const MessageType3& msg );
    virtual void handleMessage( const MessageType4& msg );
};

If new messages are added to the system AbstractHandler must be updated along with all derived types.

Alternatively I could hold all supported message types in an mpl sequence, and use mpl::inherit_linearly to generate the abstract base class.

( Note: I already use an mpl::vector of message types elsewhere in the code. )

e.g:

typedef mpl::vector< MessageType1, MessageType2, 
                     MessageType3, MessageType4 > message_types;

template< class Message >
class Wrapper
{
public:
   virtual void handleMessage( const Message& msg ) = 0;
protected:
   ~Wrapper(){}
};

class AbstractHandler 
     : public mpl::inherit_linearly< message_types
                                   , mpl::inherit< mpl_1, Wrapper< mpl::_2 > >
                                   >::type
{
public:
    virtual ~AbstractHandler() {}
};

Concrete handlers then derive from AbstractHandler. This means that whenever new message types are added to the system it is simply a case of changing the mpl::vector< types... > message_types sequence, add adding new handleMessage functions to derived classes.

In my opinion this reduces long term maintenance, since the AbstractHandler will automatically have pure virtual functions for all messages in the mpl::vector message_types

In terms of performance are there any downsides to using this approach?

What are the implications of using mpl::inherit_linearly to generate abstract base classes?

Potboy answered 13/11, 2012 at 9:54 Comment(0)
C
3

I've done similar code before (and I'm doing it again today).

There is no cost other than the inheritance-induced costs. Mainly because the final type is determined at compile time, not runtime.

However, this obviously can make your compilation time longer, relative to the message type list size. If like me you also write a message dispatcher class (which can take anything to dispatch to any handler for this type), then it can be expensive on compilation time.

Otherwise, it's good.

Just understand the implication of this kind of setup: the list of messages handled is defined at compile time, not runtime. Some event system are runtime because of the usage requirements. So make sure it's what you want in your use cases.

Cataphyll answered 21/11, 2012 at 16:56 Comment(2)
thanks for confirming my thoughts on this. I now have a working solution that is part of an API that client services use when processing messages. So far all users like the API... MPL certainly helps produce robust code...Potboy
On user side it have some drawbacks though: it's less obvious what functions have to be defined. A good (recent) compiler will make a clear message so I guess it's ok. It would also be better if there was a way to force the user to explicitely override the functions (to make sure they don't make mistakes).Cataphyll

© 2022 - 2024 — McMap. All rights reserved.