1. 程式人生 > >boost庫學習:事件處理

boost庫學習:事件處理

訊號 Signals

訊號總是與訊號處理器聯絡在一起,或者說,事件總是繫結到用於處理它的事件處理器中。

簡單使用

#include <boost/signals2/signal.hpp> // 舊的庫可能是 #include <boost/signal.hpp> 
#include <iostream>

void func()
{
  std::cout << "Hello, world!" << std::endl;
}

int func1(int num)
{
  std::cout << num << std::endl;
}

int main()
{
  boost::signals2::signal<void ()> s; // 舊的庫可能是boost::signal<void ()> s;
  boost::signals2::signal<int (int)> s2;
  s.connect(func);
  s2.connect(func1);
  s();
  s2(1);
}

以上程式碼將訊號s關聯到處理函式func。

boost::signal 是一個模板函式,模板引數是所關聯函式的簽名,以上定義,指定了void()形式的函式才能繫結到訊號s;如果signal定義的模板引數形式和connect的引數對應函式簽名不一致,或者s呼叫的方式與func定義不一致,都會報錯。

當訊號s被觸發時(呼叫s()),函式func將被呼叫。注意connect的引數func是不帶括號的。

與 boost::function 區別

以上程式碼功能用 boost::function 也能實現,但是 boost::function 只能實現一一繫結,而 signal 則可以實現一對多關係

多個函式繫結到一個訊號

#include <boost/signals2/signal.hpp> 
#include <iostream> 

void func1() 
{ 
  std::cout << "first" << std::endl; 
} 

void func2() 
{ 
  std::cout << "second" << std::endl; 
} 

int main() 
{ 
  boost::signals2::signal<void ()> s; 
  //s.connect(func1); 
  //s.connect(func2);
  // 按照關聯的順序呼叫 
  //s(); 
  
  s.connect(1, func1); 
  s.connect(0, func2);                                         
  // 按照第一個引數指定優先順序,值越小越優先 不連續也可以
  s();
} 

以上程式碼將訊號s繫結到func1和func2,如果是 s.connect(func1) 的繫結方式,則按connect順序呼叫函式;如果是 s.connect(1, func1); 的方式,則根據第一個引數(1)指定優先順序呼叫函式,值越小越優先(不連續的值也可以,例如以下程式碼)。

 s.connect(3, func1); 
 s.connect(1, func2);   

如果有興趣還可以這樣:

boost::signals2::signal<void ()> s;
s.connect(func1);
s.connect(func2);
s.connect(func1);
s.connect(func2);
s.connect(2, func1);
s.connect(3, func1);
s.connect(5, func2);
s();

看看有沒有什麼發現,我還沒看出啥規律……

將訊號與函式解綁

#include <boost/signals2/signal.hpp>                           
#include <iostream>

void func1()
{
  std::cout << "first" << std::endl;
}

void func2()
{
  std::cout << "second" << std::endl;
}

int main()
{
  boost::signals2::signal<void ()> s;
  s.connect(func1);
  s.connect(func2);
  std::cout << "conn num:" << s.num_slots() << std::endl; // 已關聯函式數量
  std::cout << "empty:" << s.empty() << std::endl; // 是否沒有任何關聯
  s.disconnect(func2);  // 釋放func2的關聯
  std::cout << "conn num:" << s.num_slots() << std::endl;
  std::cout << "empty:" << s.empty() << std::endl;
  s.disconnect_all_slots(); // 釋放所有關聯
  std::cout << "conn num:" << s.num_slots() << std::endl;
  std::cout << "empty:" << s.empty() << std::endl;
}
                                                               

相關函式有:disconnect、num_slots、empty、disconnect_all_slots

函式返回值

如果訊號綁定了兩個函式,且兩個函式都有返回值,那麼訊號觸發的結果輸出到標準輸出流,將會是最後一個函式的返回值。

#include <boost/signals2/signal.hpp>                                                                                                                                          
#include <iostream>

int func1()
{
  return 1;
}

int func2()
{
  return 2;
}

int main()
{
  boost::signals2::signal<int ()> s;
  s.connect(func1);
  s.connect(func2);
  std::cout << s().value() << std::endl;  // 參考教程直接呼叫s()會報錯,可能是版本問題,根據錯誤資訊找到boost原始碼,檢視 boost/optional/optional.hpp 檔案result_type 的介面即可
}

結果輸出2

合成器

如果需要對已繫結所有函式的返回值都處理,則需要定義合成器,並將其例項作為第二個引數傳遞給 boost::signals2::signal

#include <boost/signals2/signal.hpp> 
#include <iostream> 
#include <algorithm> 

int func1() 
{ 
  return 1; 
} 
int func2() 
{ 
  return 2; 
} 

template <typename T> 
struct max_element 
{ 
  typedef T result_type; 

  template <typename InputIterator> 
  T operator()(InputIterator first, InputIterator last) const 
  { 
    return *std::max_element(first, last); 
  } 
}; 

template<typename T>
struct maximum
{
  typedef T result_type;

  template<typename InputIterator>
  T operator()(InputIterator first, InputIterator last) const
  {
    // If there are no slots to call, just return the
    // default-constructed value
    if(first == last ) return T();
    T max_value = *first++;
    while (first != last) {
      if (max_value < *first)
        max_value = *first;
      ++first;
    }

    return max_value;
  }
};

int main() 
{ 
  boost::signals2::signal<int (), max_element<int> > s; 
  boost::signals2::signal<int (), maximum<int> > s2; 
  s.connect(func1); 
  s2.connect(func1); 
  s.connect(func2); 
  s2.connect(func2);  
  std::cout << s() << std::endl; 
  std::cout << s2() << std::endl; 

} 

以上程式碼 max_element 的輸出和預想的不符,還沒看出問題……

合成器也可以儲存所有返回結果

#include <boost/signals2/signal.hpp>                                 
#include <iostream>
#include <algorithm>
#include <vector>

int func1()
{
  return 1;
}
int func2()
{
  return 2;
}

template<typename T>
struct maximum
{
  typedef T result_type;

  template<typename InputIterator>
  T operator()(InputIterator first, InputIterator last) const
  {
    return T(first, last);
  }
};

int main()
{
  boost::signals2::signal<int (), maximum<std::vector<int> > > s2;
  s2.connect(func1);
  s2.connect(func2);
  std::vector<int> v = s2();
  std::cout << v.size() << std::endl;
}

 

連線 Connections

boost::signals::connection 型別

 connect() 會返回一個 boost::signals::connection 型別的值

 

參考:

Boost C++ 庫 第 4 章 事件處理

官方文件