Overriding a generic method of the same template base class inherited several times

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<> // This line makes me suspicious void MyClass::ListensToEvent<0>::cb(int value) { /*... callback for event 0 ...*/ } template<> void MyClass::ListensToEvent<2>::cb(int value) { /*... callback for event 2 ...*/ } 

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?

+5
source share

Source: https://habr.com/ru/post/1261260/


All Articles