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 型別的值
參考: