2012-05-02 4 views
2

私は多くのリンクされたオブジェクトで構成されたアプリケーションを持っています。それぞれのオブジェクトは機能するために必要なパラメータを持っています。私はコンテキストパターンを使用しているので、各オブジェクトは構築時に渡されるコンテキストオブジェクト参照に従って独自のパラメータを設定します。これは、以下の簡略化されたコード例でうまくいきます。observerパターンを実装するためにboost :: signalsを使用するにはどうすればよいですか?

私が追加しようとしている次の機能は、オブザーバパターンです。コンテキストオブジェクトのパラメータが変更されると、各サブスクライバオブジェクトに通知され、それに応じてパラメータが更新されます。しかし、信号をスロットに接続するために必要な構文を試すのが難しいです。

理想的には、サブスクライバオブジェクトを構築時にパラメータクラスに登録して、オブジェクトの存続期間中に自分自身を更新できるようにしたいと考えています(つまり、破壊時に登録解除する必要があります。彼らが範囲外になった場合に登録解除するためのRAII技術の一種)。以下は、できるだけシンプルに煮詰めたコード例です。

出力は、私が現在働いている

Processing unit 0 param = 1

Processing unit 1 param = 2

Processing unit 0 param = 11

Processing unit 1 param = 22

コードは以下の通りです...現在

Processing unit 0 param = 1

Processing unit 1 param = 2

Processing unit 0 param = 1

Processing unit 1 param = 2

目標は、それがために取得することです。あなたがそれを試してみたいのであれば、それは現在の形でうまくコンパイルされます。私の信号をスロットに接続するために必要な変更を提案してください。問題を引き起こす可能性のある設計上の問題も指摘してください。前もって感謝します。

あなたは、信号は、あなたがこれでコメントどこに接続したいときに発生updateParsを呼び出したいと仮定すると、
// 
// main.cpp 
// context_observer 
// 

#include <iostream> 
#include <sstream> 
#include <map> 

#include "boost/signals2.hpp" 

/* This class holds the parameters and is the class that I want to set 
* observable. It holds a std::map of the parameters and a simple accessor*/ 
class cParamsContext 
{  
    typedef std::map<std::string, float> myMap_t; 
    typedef boost::signals2::signal<void (cParamsContext&)> signal_t; 

    myMap_t paramMap;  


public:    
    signal_t sig; 

    cParamsContext() 
    { 
     paramMap["a0"] = 1.f; 
     paramMap["a1"] = 2.f;     
    } 


    float getParam(std::string key, float const & defaultVal) 
    {   
     myMap_t::iterator it = paramMap.find(key); 
     if (it == paramMap.end()) 
      return defaultVal; 
     else 
      return it->second; 
    } 

    void changePars() 
    { 
     paramMap["a0"] = 11.f; 
     paramMap["a1"] = 22.f; 
     sig(*this); 
    }  
}; 

/* This is an example of a processing class that I would like to have 
* subscribe to the parameter class.*/ 
class cProcessingUnit 
{ 
    float parameter; 
    int id; 

public: 
    cProcessingUnit(cParamsContext &contextObj, int id_) : parameter (80.f), id(id_) 
    { 
     updatePars(contextObj); 
     // Something like contextObj.sig.connect ... here 
    } 

    void updatePars(cParamsContext &contextObj) 
    { 
     std::stringstream idStream; 
     idStream << id;   
     std::string key = std::string("a" + idStream.str());      

     parameter = contextObj.getParam(key, parameter); 
    } 

    float getParam() {return parameter;} 
}; 


/* This is a very simple main function used here for testing. It 
* instantiates 2 processing objects. The parameters are then changed 
* in the observable parameter object. The processing objects should 
* then update themselves and so the last "cout" calls should reveal the 
* new parameters. At least, this is what I would like to happen!*/ 
int main(int argc, char *argv[]) 
{ 
    cParamsContext contextObj;  

    cProcessingUnit temp0(contextObj, 0); 
    cProcessingUnit temp1(contextObj, 1); 

    std::cout << "Processing unit " << 0 << " param = " << temp0.getParam() << std::endl; 
    std::cout << "Processing unit " << 1 << " param = " << temp1.getParam() << std::endl; 

    contextObj.changePars(); 

    std::cout << "Processing unit " << 0 << " param = " << temp0.getParam() << std::endl; 
    std::cout << "Processing unit " << 1 << " param = " << temp1.getParam() << std::endl;  
} 

答えて

3

// Something like contextObj.sig.connect ... here 
contextObj.sig.connect(boost::bind(&cProcessingUnit::updatePars, this, _1)); 

あなたはあなたがしているときに切断することができるように返され、接続を維持する必要があるかもしれません破壊されました。あなたの質問は本当にうまく言い表されていませんので、もしあなたが本当に必要なものかどうかを言うのは難しいです。

基本的に、信号に接続するには、信号のシグネチャと一致する「呼び出し可能なエンティティ」を渡す必要があります。これはバインダー(バインドなどの結果)、フリー関数、ラムダ式...カスタム関数子など...

私の最新のブログエントリはいくつかのヘルプのかもしれませんが、むしろ迅速かつ表面的です。

+0

おかげで私を押すため@Crazyエディへ

class cProcessingUnit { float parameter; int id; boost::signals2::scoped_connection c; public: cProcessingUnit(cParamsContext &contextObj, int id_) : parameter (80.f), id(id_) { updatePars(contextObj); c = contextObj.sig.connect( boost::bind(&cProcessingUnit::updatePars, this, _1) ); } 

多くの感謝!質問の文句については申し訳ありません。私がboost :: signalsについて非常に忠実でないとき、それをうまく定式化するのは難しいです。私はあなたのブログをチェックします。あなたが投稿したコードは、次のコンパイルエラーを返します... – learnvst

+0

main.cpp:コンストラクタ 'cProcessingUnit :: cProcessingUnit(cParamsContext&int)': – learnvst

+0

main.cpp:60:エラー: 'bind()ブースト/ブースト/バインド/バインド]を選択します。boost :: _ bi :: bind_t boost :: _ bi :: unspecified、F、typename boost :: _ bi :: list_av_2 :: type> boost :: bind(F、A1、A2):hpp:1480:メモ:候補は次のとおりです。ブースト:boost:arg:<1>] – learnvst

2

探している人は、スコープでこれを行う方法は、上記のcProcessingUnitクラスの最初の部分を次のように変更することです。 。 。答えを正しい方向に

関連する問題