I am trying to implement a generic templated observer pattern in C++11. The target is to provide a mechanism for any class member function to be registered as a callback to the observer. The observer template is as following:
template <typename... Args>
class tsubject {
public:
/// @brief Register a member function of any class as callback to the subject.
template <typename AnyObserver>
void register( AnyObserver* observer, void(AnyObserver::*func)(Args... ) ) {
register( [=]( Args... args ) {
( observer->*func )( args... );
});
}
/// @brief Register an std::function as callback to the subject.
void register( std::function<void(Args...)> const & func ) {
mCallbacks.push_back( func );
}
/// @brief Notify all registered observers
void update( Args... p ) {
for( auto it : mCallbacks ) {
it( p... );
}
}
private:
std::vector<std::function<void(Args...)> mCallbacks;
};
Usage:
class MyObserverClass {
public:
void callback( std::string arg1, int arg2 ) {
std::count << "callback:" << arg1 << ":" << arg2 << std::endl;
}
}
int main( ) {
tsubject<std::string, int> subject;
MyObserverClass observer;
subject.register( &observer, &MyObserverClass::callback );
subject.update( "test", 1 );
}
Output:
callback: test:1
Issue:
int main( ) {
tsubject<std::string, int> subject;
MyObserverClass observer;
subject.register( &observer, &MyObserverClass::callback );
subject.register( &observer, &MyObserverClass::callback );
subject.update( "test", 1 );
}
Output:
callback: test:1
callback: test:1
The issue with this implementation is that if the same observer method is registered multiple times, the callback is triggered multiple times. Since C++11 pointer to member functions are not normal pointers, they cannot be type-casted to void* for later comparison and since this is a variadic template functions, an std::map cannot be used for mCallback since the type cannot be specified. Is there any mechanism possible to avoid multiple registration elagantly?
Aucun commentaire:
Enregistrer un commentaire