signals2

概念

  • 插槽可以是函数指针、函数对象、bind表达式、function对象。调用signals的成员函数connect()来将插槽连接到信号上,相当于为信号注册一个处理的handler。对signal对象调用()即为产生一个信号(signal提供了operator()),从而导致连接的所有插槽被调用。产生信号即调用signal的operator()的返回值是一个optional类型的对象,可以使用解引用操作符*来获得真正的返回值,而且默认情况下,这个返回值是最后被调用的插槽的返回值。signal会把参数传递给所有连接的插槽。
  • 就像function一样,signal也是一个模板类,第一个模板参数是插槽函数类型签名,除了第一个模板参数外其他的模板参数都有缺省值,所以可以只传入第一个参数。
  • signal::connect()的第一个参数为一个插槽,第二个参数为插入的位置,插入位置决定了插槽的调用顺序,默认值为at_back往后插入,at_front为往前插入,返回值是一个connection对象,可以这个对象来管理连接,如断开连接(disconnect)、测试连接(connected)等。
  • 其它成员函数:
  • num_slots()用来获得连接的插槽的个数,empty()用来判断连接的插槽数量是否为0。
  • combiner()用来获取合并器,set_combiner()用来设置合并器,不过一般是在signal构造函数中直接设置合并器。
  • disconnect()用来断开连接,disconnect_all_slots()用来断开所有连接的插槽,signal对象析构时会自动调用disconnect_all_slots()。
#include "boost/signals2.hpp"

int slots1(int n)
{
    int iRet = n * n;
    cout << "slot1 called, return value: " << iRet << endl;
    return iRet;
}

int slots2(int n, int x)
{
    int iRet = n * n * x;
    cout << "slot2 called, return value: " << iRet << endl;
    return iRet;
}

int slots3(int n)
{
    int iRet = n * n;
    cout << "slot3 called, return value: " << iRet << endl;
    return iRet;
}

int slots4(int n)
{
    int iRet = n * n;
    cout << "slot4 called, return value: " << iRet << endl;
    return iRet;
}

int main()
{
    boost::signals2::signal<int(int)> sig;

     //sig.connect(&slots1);
     //sig.connect(&func,boost::signals2::at_front); 
     //sig.connect(1,&func_,boost::signals2::at_front); 组号
     //sig.connect(&slots1);
    boost::signals2::connection con1 = sig.connect(slots1);
    boost::signals2::connection con2 = sig.connect(bind(slots2, _1, 100));
    boost::signals2::connection con3 = sig.connect(slots3, boost::signals2::at_front);
    boost::signals2::connection con4 = sig.connect(slots4);

    bool b = con4.connected();
    con4.disconnect();
    b = con4.connected();

    int iRet = *sig(1);
    cout << "return value: " << iRet << endl;

    return 0;
}

模板参数

  • 前边我们说过,signal是一个模板类,它的第一个模板参数是插槽函数类型签名,其余模板参数都有缺省值。

  • ①、signal<>的第二个模板参数

  • 默认情况下,产生信号即调用signal对象的operator()的返回值是最后被调用的插槽的返回值,eg:

#include "boost/signals2.hpp"

template<int N>
class MySlots //模板函数对象类,可以用来生成一系列的插槽
{
public:
    int operator()(int x)
    {
        cout << "slot" << N << " called" << endl;
        return x * N;
    }
};

int main()
{
    boost::signals2::signal<int(int)> sig;

    boost::signals2::connection con4 = sig.connect(MySlots<3>());

    int iRet = *sig(10); //iRet为30

    return 0;
}
  • signal<>的第三个模板参数

  • connect()时未被编组的插槽如果位置标志是at_front则在所有插槽调用之前调用,at_back为在所有插槽调用之后调用。

  • 例如以下代码,插槽的调用顺序为:slots5, slots1, slots6, slots3, slots2, slots4

    boost::signals2::signal<void(int)> sig;
    boost::signals2::connection con1 = sig.connect(1, &slots1);
    boost::signals2::connection con1 = sig.connect(1, &slots6);
    boost::signals2::connection con2 = sig.connect(3, &slots2);
    boost::signals2::connection con3 = sig.connect(2, &slots3);
    boost::signals2::connection con4 = sig.connect(&slots4);
    boost::signals2::connection con5 = sig.connect(&slots5, boost::signals2::at_front);

    sig(100);