2011-07-23 7 views
1

最近、私はboost::signalを隠す柔軟なオブザーバパターンの実装を作成しようとしていました。私はほぼ成功した。テンプレートシグネチャからboost :: functionを作成する方法

私は、Observerクラスを持っています。これは、テンプレートパラメータによって提供されるupdateメソッドシグネチャと一致するメソッドを持つ必要があります。使用の

例:observerupdateメソッドをオーバーロードしていない場合は

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); 

すべてがうまく動作します。この場合、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は、この問題を解決するのに役立つことができると思います。テンプレートの署名だけを使って正しいメンバメソッドとバインドする方法がわかりません。

それは可能ですか?

答えて

0

いいえ、boost :: functionは役に立ちません。 13.4.3は

非スタティックメンバ関数は、タイプ のターゲット一致言う「ポインタ・ツー・メンバ関数と、」 体へのポインタの機能の種類が過負荷 のセットからのメンバ関数を選択するために使用されますメンバー関数

これは、オーバーロードされたメンバ関数のアドレスを取る関数オブジェクト(テンプレートまたはない、ブーストまたは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は既にこのような変換テンプレートを持っている可能性がありますが、見つかりませんでした。

+0

ありがとうございます。あなたのソリューションは美しく動作します。 :) – Wojciech

関連する問題