我正在尝试在C ++ 11中实现通用的模板化观察者模式。目标是为任何类成员函数提供一种机制,使其能够注册为对观察者的回调。观察者模板如下:
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;
};
用法:
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 );
}
输出:
callback: test:1
问题:
int main( ) {
tsubject<std::string, int> subject;
MyObserverClass observer;
subject.register( &observer, &MyObserverClass::callback );
subject.register( &observer, &MyObserverClass::callback );
subject.update( "test", 1 );
}
输出:
callback: test:1
callback: test:1
此实现的问题在于,如果多次注册相同的观察者方法,则会多次触发回调。由于C ++ 11指向成员函数的指针不是普通指针,因此无法将它们类型转换为void *以供以后比较,因为这是一个可变参数模板函数,所以std :: map不能用于mCallback,因为该类型不能指定。是否有任何机制可以避免多次注册?