Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically setup a template class method in C++?

Tags:

c++

templates

There is a class that generates an event with variable-type data from time to time.

class A 
{
  void reportEvent(auto event);
};

I want to generalize this class and make it possible to assign various event handlers.

class A 
{
  EventHandler _eventHandler();
  void reportEvent(auto event) 
  {
    _eventHandler.processEvent(event);
  } 
};

But it's not possible to make a virtual method with an auto parameter.

What can I do?

I understand that I can make class A a template class with EventHandler as a template parameter. But I don't think it's a good solution as it's a big class, and reporting events is just a bit of its functionality. It looks like an abuse of template instrumentality here for me. Are there other workarounds?

like image 512
ephemerr Avatar asked Dec 22 '25 06:12

ephemerr


1 Answers

I assume that the list of event types is well defined and you can enumerate them. If you don't want to use templates and run-time dispatch is fast enough you can deploy the visitor pattern.

First you define a common base class for all your event handlers:

class AbstractEventHandler {
    public:
       virtual void processEvent(EventTypeA a) = 0;
       virtual void processEvent(EventTypeB b) = 0;
       ... //you list all possible event types
};

Then, all your actual event handlers derive from the AbstractEventHandler and must implement all processEvent-s variants. For example:

class LogEventHandler : public AbstractEventHandler {
    public:
        void processEvent(EventTypeA a) final {
            std::cout << "Event A happened\n";
        }
        void processEvent(EventTypeB b) final {
            std::cout << "Event B happened\n";
        }
};

Finally, in the class A you need to keep the event handler as a pointer, rather than a direct field. This is because various versions of the handler may differ in size.

class A {
     public:
         A(std::unique_ptr<AbstractEventHandler> handler) : handler_(std::move(handler)) {}
         void reportEvent(auto event) {
            handler_->processEvent(event);
         }
     private:
         std::unique_ptr<AbstractEventHandler> handler_;
};

It should be noted what to expect when some time in the future you introduce a new event type:

  • If you just call A::reportEvent with a new type, a compile error will occur at ->processEvent, stating that the compiler cannot find the right overload among the virtual functions of the abstract class.

  • When you then add the required processEvent into the list in the AbstractEventHandler, you will get compile errors with all the actual event handlers stating that an implementation is missing.

  • Then you will have to provide the actual implementation in all handlers, making the code complete.

This way, compile errors guide you what you should do next. However, if most event handlers should process only one type and you find implementing empty functions for other types is tedious, you could replace =0 with an empty function {} in the AbstractEventHandler.

When you do, compiler won't complain about processEvent not being implemented in the derived handlers and just default to empty function instead. Less boilerplate, but you might forget adding the implementation when you actually do need it.

like image 143
CygnusX1 Avatar answered Dec 24 '25 00:12

CygnusX1