mercredi 20 novembre 2019

virtual method callbacks in C++11/14/17?

I have some subscription function that will call my callback when something happens. (Let's say it's a timer, and will pass me an object when a certain number of milliseconds elapses.) The thing I want to be called is a virtual method. I feel std::function and std::bind or lambdas are part of the solution.

The C++99 approach I've used until now involves one-line C functions that know how to call a virtual method. The subscription function takes the C function and a void* user data as arguments. For example:

class Foo {
  virtual void OnTimerA( Data* pd );
};

void OnTimerACB( Data* pd, void* pvUserData ) {
  ( (Foo*) pvUserData )->OnTimerA( pd );
}

/* Inside some method of Foo; 1000 is a number of milliseconds to call me back in;
   second arg is a function pointer; third is a void* user data that is passed back
   to the C callback. */
SubscribeToTimerOld( 1000, OnTimerACB, this );

What I'm hoping for is a way to write:

SubscribeToTimerNew( 1000, OnTimerA );

or something similar, at least that disposes of the need to write that one-line C binding callback.

I have a feeling that SubscribeToTimerNew()'s argument is probably a std:function of some sort and instead of merely writing OnTimerA I'd have to write something with std::bind to get the this pointer in there.

Alternatively to bind, perhaps a lambda is the way to do it? This compiles, though I dont see how to extend it to let the event handler pass an argument to OnTimerA(). (My linker isn't currently working so don't know if it links or runs as desired.)

SubscribeTimer(  1000, [this](){this->OnTimerA();} );

To mention one alternative I've discarded: give Foo a superclass with a method called OnTimer() that will be called when the timer goes off. Now SubscribeTimer() only need take an elapsed time. I don't like this as it doesn't cleanly allow for multiple timers to be registered. If it did you could give them (say) integer timer ID's and implement OnTimer() as a switch but this seems to be a lot more complicated than the C++99 solution.

Ultimately of the (I assume) several approaches, are there any trade-offs (e.g., heap use) in addition the most obvious question of how much typing is involved? (This is a high-performance application and I'd prefer to minimize or eliminate heap usage.)

Aucun commentaire:

Enregistrer un commentaire