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 言う

非静的メンバー関数は、型「pointer-to-member-function;」のターゲットに一致します。メンバーへのポインターの関数型は、オーバーロードされたメンバー関数のセットからメンバー関数を選択するために使用されます。

これは、オーバーロードされたメンバー関数のアドレスを取得して、それを任意の種類の関数オブジェクト (テンプレート化されているかどうか、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 に答える