2012-05-02 29 views
2

我有一個應用程序由許多鏈接的對象組成,每個鏈接對象都有它們需要的參數才能起作用。我正在使用上下文模式,以便每個對象根據構建時給出的上下文對象參考設置自己的參數。這在下面給出的簡化代碼示例中運行良好。如何使用boost :: signals來實現觀察者模式?

我試圖添加的下一個功能是觀察者模式,以便當上下文對象中的參數發生更改時,會通知每個訂閱服務器對象並相應地更新其參數。但是,我無法解決爲了將信號連接到插槽而需要使用的語法。

理想情況下,我希望訂閱者對象在構造時向參數類註冊自己,以便他們可以在對象的生命週期內更新自己(即他們必須在銷燬時註銷自己,或者更好地使用一些如果RAII技術超出了範圍,那麼可以註銷自己的RAII技術)。下面是一個代碼示例,我希望儘可能簡化。

輸出是目前

Processing unit 0 param = 1

Processing unit 1 param = 2

Processing unit 0 param = 1

Processing unit 1 param = 2

的目標是得到它是...

Processing unit 0 param = 1

Processing unit 1 param = 2

Processing unit 0 param = 11

Processing unit 1 param = 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;  
} 

回答

3

假設你要撥打updatePars當信號觸發你連接,你這個評論:

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

您可能需要保持連接返回,所以你可以斷開,當你銷燬。你的問題雖然措辭不是很好,但很難說這是否是你真正需要的。

基本上,連接到你需要通過它的信號的簽名相匹配的「可調用實體」的信號。這可以是一種粘合劑(綁定的結果和其他幾個人),一個自由的功能,lambda表達式...定製的仿...等等...

我最近的博客條目可能有一定的幫助,但它相當快速和表面。

+0

感謝您的回答!對這個問題的措辭感到抱歉。當我對boost :: signals非常無知時,很難很好地表達它。我會檢查你的博客。您發佈的代碼給出了以下編譯錯誤: – learnvst

+0

main.cpp:在構造函數'cProcessingUnit :: cProcessingUnit(cParamsContext&,int)'中: – learnvst

+0

main.cpp:60:錯誤:沒有用於調用'bind(<未解決的重載函數類型>,cProcessingUnit&,升壓:: ARG <1>&)」 /編程/軟件開發工具包/升壓/升壓/結合/綁定。hpp:1480:注意:候選是:boost :: _ bi :: bind_t :: type> boost :: bind(F,A1,A2 )[with F = void(cProcessingUnit :: *)(cParamsContext&),A1 = cProcessingUnit,A2 = boost :: arg ] – learnvst

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埃迪推我在正確的方向