最近我正在尝试创建隐藏boost::signal
的灵活的观察者模式实现。我几乎成功了。
我有一个 Observer
类,它必须有一个 update
方法匹配模板参数提供的签名。
使用示例:
Observable<void(float, float)> observable;
Observer<void(float, float)> observer;
observable.attach(&observer);
observable.notify(Observable::Arguments(10.0f, 1.0f)); // invokes observer->update(10.0f, 1.0f);
如果 observer
没有重载 update
方法,一切正常。在这种情况下,boost::bind
无法推断出正确的使用方法。不幸的是,我不能使用显式转换,因为我不知道更新参数(此信息在 FunctionSignature
中)。
以下方法会引起麻烦:
class Observable <typename FunctionSignature>
{
...
template <class DerivedObserverClass>
void attach(DerivedObserverClass* observer)
{
STATIC_ASSERT((boost::is_base_of<ObserverType, DerivedObserverClass>::value));
ConnectionsMap::iterator it = connections.find(observer);
if (it == connections.end() || !it->second.connected()) {
// i would like to do something like
// boost::function<FunctionSignature> f;
// f = boost::bind(&static_cast<FunctionSignature>DerivedObserverClass::update, observer, _1);
// singnalSlot is defined as boost::signal<FunctionSignature>
// this works as long, as Derived class doesn't have overloaded update method
connections[observer] = signalSlot.connect(boost::bind(&DerivedClass::update, observer, _1));
} else {
throw std::invalid_argument("Observer already attached.");
}
}
我认为 boost::function
可以帮助解决这个问题。我不知道如何仅使用模板签名将其与正确的成员方法绑定(bind)。
有可能吗?
最佳答案
不,boost::function 也帮不了你。 13.4.3 说
Nonstatic member functions match targets of type “pointer-to-member-function;” the function type of the pointer to member is used to select the member function from the set of overloaded member functions.
这意味着您不能获取重载成员函数的地址,将其传递给任何类型的函数对象(模板化或非模板化,boost 或 std 或其他),并希望重载能够自行解决。您需要在赋值的左侧有一个真正诚实的指向成员函数的指针类型。
您必须以某种方式将您的 FunctionSignature
转换为指向成员函数的指针类型。这里有一些老式的模板魔术,可以满足您的需求,只需要有限数量的函数参数。 c++0x 可能有更好、更通用的解决方案。
template <typename C, typename F>
struct tomemfun;
template <typename C, typename res>
struct tomemfun<C, res()>
{
typedef res (C::*memfun_t)();
};
template <typename C, typename res, typename arg1>
struct tomemfun<C, res(arg1)>
{
typedef res (C::*memfun_t)(arg1);
};
template <typename C, typename res, typename arg1, typename arg2>
struct tomemfun<C, res(arg1, arg2)>
{
typedef res (C::*memfun_t)(arg1, arg2);
};
// repeat with more arguments as needed
现在你可以使用
tomemfun<DerivedClass, FunctionSignature>::memfun_t update = &DerivedClass::update;
它将解析为正确的重载函数。
boost
可能已经有这样的转换模板,但我找不到。
关于c++ - 如何从模板签名创建 boost::function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6798742/