Background
I came across an application where I had access to a method:
void AttachCallback(int event, std::functional<void(int)> cb);
which allowed me to attach a cb callback to the event event . I also had several classes that would attach callbacks to pairs of events in their constructors and implement a callback for each event associated with it. So, the first implementation that comes to mind looks like this:
class MyClass { public: MyClass() { AttachCallback(0, [this](int value) { cb0(value); }); AttachCallback(2, [this](int value) { cb2(value); }); // ... as necessary } private: void cb0(int value) { /*... callback for event 0 ...*/ } void cb2(int value) { /*... callback for event 2 ...*/ } // ... as necessary };
But, since I played a lot with templates recently, I wondered if I could create a template virtual class to listen for this event and use it as follows:
template<const int EVENT> class ListensToEvent { public: virtual ~ListensToEvent() = default; protected: ListensToEvent() { AttachCallback(EVENT, [this](int value) { cb(value); }); } virtual void cb(int value) = 0; }; class MyClass : public ListensToEvent<0>, public ListensToEvent<2> { private: void cb(int value) override; }; template<>
When searching related topics, I found this thread that shows how to use helper classes to resolve conflicts that arise when two base interfaces provide the same identifier as a pure-virtual method. Since I use templates here, I would not be able to use such helpers, because I do not know how many instances there could be, but I found that declaring a method without specialization and then providing specialized templates outside the class definition allowed me to take an individual approach to each base class method (as shown above).
Proof of concept
During testing, I built a simplification of this project (without callbacks) to show that it compiles and specializes here .
Question
First of all, I'm interested in my understanding of why this works. It makes sense to me that I can specify which cb I am implementing after defining the class by assigning cb either ListensToEvent<0> or ListensToEvent<2> . I donβt understand why this qualification is considered a template specification and therefore the template<> line is needed. Also, if these qualifications are in fact specialized specializations, how exactly does C ++ consider method specialization and why do they work?
With that said, I'm also interested in comments on the functionality of this design. Is this an effective way to simplify MyClass and its implementation by other siblings, or would it be better to make the first method I suggested? Or is there another design that would work best in this situation?