C ++ Boost signal2 signal / slot function

signals2 based Boost in another library signals, to achieve a thread-safe observer mode. It is a callback mechanism, when a signal is associated with a plurality of grooves, signals sent, these slots will be called, of course, also only one groove associated function.

In fact, Qt also provides its own signals and slots mechanism, that is very flexible and easy to use, but it depends on the Qt framework, so the next best thing, chose to Boost provides signals2;

signals2 the namespace library boost :: signals2 in order to use it, need to include header <boost / signals2.hpp>;


Signal (Signal)
signal can not be copied, if the signal as a member variable of the class, then the class will not be copied, unless reference only intelligent or indirectly held by it;

signal class is a template, it is defined as follows:

template<typename Signature, 
typename Combiner = boost::signals2::optional_last_value<R>, 
typename Group = int, typename GroupCompare = std::less<Group>, 
typename SlotFunction = boost::function<Signature>, 
typename ExtendedSlotFunction = boost::function<R (const connection &, T1, T2, ..., TN)>, 
typename Mutex = boost::signals2::mutex> 
class signal;

The first Signature template parameter meaning and function the same, is also a function type represents a function call signal (slot, event processing handler), for example:

signal <void (int, double) > sig;
second template parameter Combiner is a function object, it is called "combiner", the return value for all combinations of the groove, the default is to boost :: signals2 :: optional_last_value < R>, and finally returns the return value is called a groove;

The third template parameter Group is a grouping of slot type, you can set up different groups for your tank, the type of the default group is int, under normal circumstances, no change;

 

Connect (Connect)
Connection Connect (const Group group_type &, const the slot_type & slot, connect_position = at_back position)
as the member function signal having three parameters, the first parameter set belongs groove, the second trigger signal indicates a parameter which slot function, and the last parameter indicates the position of the slot function response in the response queue, the default at_back indicates that this function out of the groove end of the queue, it will be called after the other slot function.

Examples
without return value of the slot function

#include <iostream>
#include <boost/signals2.hpp>
using namespace boost::signals2;
void slots1() {
std::cout << "slot 1 called" << std::endl;
}

void slots2(int a) {
std::cout << "slot 2 called " << a << std::endl;
}

void slots3(int a) {
std::cout << "slot 3 called " << a << std::endl;
}

void slots4(int a) {
std::cout << "slot 4 called " << a << std::endl;
}

int main() {
signal<void()>sig1;
sig1.connect(&slots1);
sig1(); // the slot 1 called
signal<void(int)>sig2;
sig2.connect(1, &slots2);
sig2.connect(2, &slots3);
sig2.connect(2, &slots4, at_front); // slot 4 处于 第二组的最前面
//Function call to the groove, has a first group of comparison sequentially connected, and sequential call according to the group; 
SIG2 ( 2 ); // slot 2 Called slot. 4 Called slots3 Called 
return  0 ; 
}

When the number of coincident grooves function with parameters, the parameters are transmitted by the signal, it is necessary to maintain the parameter signal and groove

The results are as follows:

 

 

 

Slot function with parameters

#include <iostream>
#include <boost/signals2.hpp>
using namespace boost::signals2;
int slots1(int a) {
std::cout << "slot 1 called " << a << std::endl;
return a + 1;
}

int slots2(int a) {
std::cout << "slot 2 called " << a << std::endl;
return a + 2;
}

int slots3(int a) {
std::cout << "slot 3 called " << a << std::endl;
return a + 3;
}

int main() {
signal<int(int)> sig;
sig.connect(&slots1);
sig.connect(&slots2, at_front);
sig.connect(&slots3);
std::cout << *sig(0) << std::endl;
return 0;
}

By default, a plurality of signal connection slot function, and the groove is a function with a return value, then this last signal will return a return value of the function in the queue slot.

The results are as follows:

 

 

 Combiner

Custom merger allows us to handle the return value of a plurality of slots;

template<typename T>
struct Combiner {
typedef vector<T> result_type;
template<typename InputIterator>
result_type operator()(InputIterator first, InputIterator last) const {
if(first == last) {
return result_type(0);
}
return result_type(first, last);
}
};

This is a typical merger, it returns a return value of a vector has all the slots, we can easily define the merger's return type, but be careful, must pass typedef your_type result_type to register at your return type;

Specific usage is as follows:

#include "boost/signals2.hpp"
#include <iostream>
#include <vector>
using namespace std;
using namespace boost::signals2;

template<typename T>
struct Combiner {
typedef vector<T> result_type;
template<typename InputIterator>
result_type operator()(InputIterator first, InputIterator last) const {
if(first == last) {
return result_type(0);
}
return result_type(first, last);
}
};

int slots3(int x) {
return x + 3;
}

int slots4(int x) {
return x + 4;
}

int main() {
signal<int(int), Combiner<int> > sig;
sig.connect(&slots3);
sig.connect(&slots4);
auto result = sig(1);
for(const auto& i : result) {
cout << i << endl;
} 
return 0;
}

 

Disconnect

// above to abbreviate 
sig.connect ( 0 , & slots1); 
sig.connect ( 0 , & slots2); 
Connection C1 = sig.connect ( . 1 , & slots3); 
sig.connect ( 2 , & slots4); 
SIG .connect ( 2 , & slots5); 
SIG (); 
sig.disconnect ( 0 ); // disconnect connection group number of 0 
COUT << sig.num_slots () << endl; // there are three connection 
SIG ( ); 
sig.disconnect ( 2 ); // disconnect group number 2 is connected 
SIG (); 
c1.disconnect (); // disconnect connection slot3

The above two methods are possible;

 

Temporary connection
Boost provides a temporary connection scoped_connection, there is scope connection;

// above some code omitted 
sig.connect (& slots1); 
{ // comes into scope establish a temporary connection 
scoped_connection 'sig.connect SC = (& slots2); 
COUT << sig.num_slots () << endl; 
} // out of scope automatically disconnected 
cout << sig.num_slots () << endl;

Blocking connection

Providing a Boost operation shared_connection_block implemented blocked and unblocked connection, when it is destructed (out of scope) or by explicitly calling unblock () like unblocked;

// above to abbreviate 
Connection C1 = sig.connect (slots1); 
Connection C2 = sig.connect (slots2); 
Connection C3 = sig.connect (slots3); 
Connection C4 = sig.connect (slots4); 
SIG (); 
{ 
shared_connection_block Block (C1); // blocked C1 
SIG (); // C1 is not called 
} 
SIG ();

 

Trigger members of slot function

We usually use the signal to communicate between the classes that implement the observer pattern;

We need to bind () function to bind slot function, the function returns an object;

#include "boost/signals2.hpp"
#include <iostream>
#include <vector>
using namespace std;
using namespace boost::signals2;

class C_Slots1 {
public:
int SL(int a) {
cout << "slot 1 called" << a << endl;
return a;
}
void SL1(int a, int b) {
cout << "slot 2 called " << a << " " << b << endl;
}
};

int main() {
signal<int(int)> sig1;
sig1.connect(bind(&C_Slots1::SL, &cs_1,_1)); // 绑定对象的成员
signal<void(int, int)>sig2;
sig2.connect(bind(&C_Slots1::SL1,&cs_1, _1, _2));
cout << *sig1(10) << endl;
sig2(1, 2);
return 0;
}

 

Automatically disconnect
when the slot function is accidentally destroyed, it will signal to call undefined behavior. We hope that it will be able to track the life cycle of the slot function, when the slot function fails, the connection will automatically disconnect;

We managed through boost :: shared_ptr life cycle of the slot function, track () function to track resource slots used; (boost :: shared_ptr and std :: shared_ptr function on the same, but the implementation is not the same, is not the same! !!)

#include "boost/signals2.hpp"
#include <iostream>
#include <vector>
using namespace std;
using namespace boost::signals2;

class C_Slots {
public:
int SL(int a) const{
cout << "slot 1 called" << a << endl;
return a;
}
};

int main() {
typedef signal<int(int)> signal_t;
signal_t sig;
boost::shared_ptr<C_Slots> p_c1(new C_Slots2());
sig5.connect(signal_t::slot_type(&C_Slots::SL, p_c1.get(), _1).track(p_c1));
cout << *sig(2) << endl;
return 0;
}

 

When a member function is a function of class slots

#include <iostream>
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
 
using namespace std;
using namespace boost;
 
template <typename signature>
class Signal{
 
public:
    //typedef 信号
    typedef boost::signals2::signal<signature> defSignal;
    typedef typename defSignal::slot_type defSlot;
 
public:
    //连接槽函数
    boost::signals2::connection connectFun(const defSlot& slot);
 
    //重载伪函数
    void  operator () (Template typename defSignal :: Arg < 0 > :: type A0, Arg typename defSignal :: Template < . 1 > :: type A1); 
 
Private : 
    defSignal mSignal; 
 
 
}; 
 
// function after receiving the signal response 
class {FunRecv1 
 
public :
     void Action ( int a, int B) { 
      COUT << " the Add Result " << a + B << endl; 
    } 
 
}; 
 
// function after receiving the response signal 
class FunRecv2 { 
 
public :
     void Action ( int a, int b){
      cout << "multi result" << a * b << endl;
    }
 
};
 
//实现
template <typename signature>
boost::signals2::connection  Signal<signature>::connectFun(const defSlot& slot){
    return mSignal.connect(slot);
}
 
template <typename signature>
void Signal<signature>::operator()(typename defSignal::template arg<0>::type a0,typename defSignal::template arg<1>::type a1){
    mSignal(a0,a1);
}
void main(){
    
    Signal<void(int,int)> mysignal;
    FunRecv1 fun1;
    FunRecv2 fun2;
 
    //boost::function<void(int,int)> myfun = boost::bind(&FunRecv1::action,&fun1,_1,_2);
    //信号连接槽函数
    boost::signals2::connection con1 = mysignal.connectFun(boost::bind(&FunRecv1::action,&fun1,100,200));
    boost::signals2::connection con2 = mysignal.connectFun(boost::bind(&FunRecv2::action,&fun2,11,22));
    mysignal(100,200);
 
    con2.disconnect();
    mysignal(100,200);
 
    cin.get();
}

 

 

Transfer: https://blog.csdn.net/qq_34347375/article/details/86620845

Guess you like

Origin www.cnblogs.com/kerngeeksund/p/11488746.html