1

最近我试图创建灵活的观察者模式实现,它隐藏了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可能有助于解决这个问题。我不知道如何仅使用模板签名将其与正确的成员方法绑定。

甚至可能吗?

4

1 回答 1

-1

不, boost::function 也无济于事。13.4.3 说

非静态成员函数匹配“指向成员函数的指针”类型的目标;成员指针的函数类型用于从重载的成员函数集中选择成员函数。

这意味着您不能获取重载成员函数的地址,将其传递给任何类型的函数对象(模板化与否,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可能已经有这样的转换模板,但我找不到。

于 2011-07-23T11:19:38.737 回答