2

私は多くのリンクされたオブジェクトで構成されるアプリケーションを持っています。それぞれのオブジェクトには、機能するために必要なパラメーターがあります。私はコンテキストパターンを使用しているので、各オブジェクトは、構築時に与えられるコンテキストオブジェクト参照に従って独自のパラメーターを設定します。これは、以下に示す簡略化されたコード例でうまく機能します。

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

理想的には、サブスクライバーオブジェクトを構築時にパラメータークラスに登録して、オブジェクトの存続期間中更新できるようにします(つまり、破棄時に登録を解除する必要があります。さらに、何らかのRAII手法を使用する必要があります。範囲外になった場合は登録を解除します)。以下は、私が可能な限り単純に要約したコード例です。

出力は現在です

処理装置0param= 1

処理装置1param= 2

処理装置0param= 1

処理装置1param= 2

目標はそれを実現することです...

処理装置0param= 1

処理装置1param= 2

処理装置0param= 11

処理装置1パラメーター=22

私が現在使用しているコードは以下のとおりです。試してみたい場合は、現在の形式で問題なくコンパイルされます。信号をスロットに接続するために必要な変更を提案してください。将来的に問題を引き起こす可能性のある設計上の問題もお気軽に指摘してください。前もって感謝します。

//
//  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;    
}
4

2 に答える 2

3

シグナルが発生したときに updatePars を呼び出したいと仮定すると、次のようにコメントした場所に接続します。

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

破棄されたときに切断できるように、返された接続を保持する必要がある場合があります。ただし、あなたの質問はあまりうまく表現されていないため、これが本当に必要かどうかを判断するのは困難です。

基本的に、シグナルに接続するには、シグナルの署名に一致する「呼び出し可能なエンティティ」を渡す必要があります。これは、バインダー (bind およびその他のいくつかの結果)、フリー関数、ラムダ式、カスタム ファンクターなどです。

私の最新のブログ エントリは役立つかもしれませんが、かなり迅速で表面的なものです。

于 2012-05-02T19:07:09.713 に答える
2

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

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

私を正しい方向に押してくれた@Crazy Eddieに感謝します

于 2012-05-02T20:11:34.393 に答える