boost::signal2筆記

     以前項目中作過一個功能就是根據一個數值變化來執行相應的策略,當時想到了訂閱者設計模式,其中最關鍵的就是事件的關聯和回溯,其實就是類型C#的委託和qt中的槽概念。原本用QT來實現又以爲繁瑣就選了一個比較普遍的庫就用了boost的signals2功能.
所須要的頭文件 :
      #include <boost/signal.hpp> 
建立第一個demo:
     下面的功能是實現建立一個signal的槽,而後咱們建立一個HelloWorld的結構體而後跟sig進行綁定,經過sig()方式能夠直接調用全部與其綁定的方法。
struct HelloWorld { void operator()() const { std::cout << "Hello, World!" << std::endl; } };
 
boost::signal<void ()>sig;
int main(int argc, const char * argv[]) {
    HelloWorld helloworld;
    sig.connect(helloworld);
    sig();
  
    return 0;
}




鏈接多個事件:

     上面的demo實現的是一個方法的鏈接,下面是一個signal鏈接多個方法,而後當調用 sig時同時執行鏈接的幾個方法。 ios

struct Hello{
    void operator()()const{
        std::cout<<"Hello ";
    }
};
struct World{
    void operator()()const{
        std::cout<<"World"<<std::endl;
    }
};
boost::signal<void ()>sig;
int main(int argc, const char * argv[]) {
 
    sig.connect(Hello());
    sig.connect(World());
    sig();
  
    return 0;
}




信號分組:
     除了上面的鏈接多個方法外,還能夠將其進行分組,經過組號來決定執行的順序。
sig.connect(1,Hello());
 sig.connect(0,World());
 sig();

上面的代碼最終輸出的World \n hello web

struct Hello{
    void operator()()const{
        std::cout<<"Hello ";
    }
};
struct World{
    void operator()()const{
        std::cout<<"World"<<std::endl;
    }
};
struct GoodMorning
{
    void operator()() const
    {
        std::cout << "... and good morning!" << std::endl;
    }
};
boost::signal<void ()>sig;
int main(int argc, const char * argv[]) {
 
    sig.connect(0,Hello());
    sig.connect(1,World());
    sig.connect(GoodMorning());
    sig();
  
    return 0;
}



在上面咱們添加了一個未分組的GoodMorning方法,咱們最終的輸出結果將其插入到尾部,,其實咱們能夠經過傳入個
enum connect_position { at_back, at_front };默認爲at_back

Slot參數

     除了上面的關聯外還能夠鏈接時傳入參數,傳入的參數會自動傳送給全部鏈接的方法中。 設計模式

/
//  main.cpp
//  signals2
//
//  Created by wenchangshou on 15/11/17.
//  Copyright © 2015年 wenchangshou. All rights reserved.
//
 
#include <iostream>
#include <boost/signal.hpp> 
void print_args(float x, float y)
{
    std::cout << "The arguments are " << x << " and " << y << std::endl;
}
 
void print_sum(float x, float y)
{
    std::cout << "The sum is " << x + y << std::endl;
}
 
void print_product(float x, float y)
{
    std::cout << "The product is " << x * y << std::endl;
}
 
void print_difference(float x, float y)
{
    std::cout << "The difference is " << x - y << std::endl;
}
 
void print_quotient(float x, float y)
{
    std::cout << "The quotient is " << x / y << std::endl;
}
boost::signal<void (float,float)>sig;
int main(int argc, const char * argv[]) {
     
    sig.connect(&print_args);
    sig.connect(&print_sum);
    sig.connect(&print_product);
    sig.connect(&print_difference);
    sig.connect(&print_quotient);
     
    sig(5., 3.);
    return 0;
}



 輸出結果:
The arguments are 5 and 3
The sum is 8
The product is 15
The difference is 2
The quotient is 1.66667
signal返回值:

     咱們不只能夠傳入參數也能夠根據傳入的參數的返回結果。 函數

#include <iostream>
#include <boost/signal.hpp> 
float product(float x, float y) { return x * y; }
float quotient(float x, float y) { return x / y; }
float sum(float x, float y) { return x + y; }
float difference(float x, float y) { return x - y; }
 
boost::signal<float (float,float)>sig;
int main(int argc, const char * argv[]) {
    sig.connect(&product);
    sig.connect(&quotient);
    sig.connect(&sum);
    sig.connect(&difference);
     
    std::cout<<sig(5., 3.)<<std::endl;
    return 0;
}



     上面的結果輸出的爲2,這是由於sig會對全部鏈接的方法進行調用,可是隻會返回最後一個執行的結果。


     下面的例子是返回其中最大的數: spa

template<typename T>
struct maximum{
    typedef  T result_type;
    template<typename InputIterator>
    T operator()(InputIterator first,InputIterator last) const{
        if(first==last)return T();
        T max_value=*first++;
        while(first!=last){
            if(max_value<*first)
                max_value=*first;
            ++first;
        }
        return max_value;
    }
};
boost::signal<float (float,float),maximum<float>>sig;



     上面的是maximum就是一個Combiner,比較全部的結果返回最大數

     有的時候咱們但願將全部槽的的返回結果放入一個組合當中 設計

template<typename Container>
struct aggregate_values{
    typedef  Container result_type;
    template<typename InputIterator>
    Container operator()(InputIterator first,InputIterator last) const{
        Container values;
        while(first!=last){
            values.push_back(*first);
            first++;
        }
        return values;
    }
};
   
std::vector<float> results=sig(5,3);
    std::copy(results.begin(), results.end(),
              std::ostream_iterator<float>(std::cout, " "));
    std::cout << "\n";




最終咱們會返回15 1.66667 8 2 
 disconnect();//取消槽鏈接
sig.connect(&foo);
  sig.connect(&bar);
  sig();

  // 取消foo而保留bar
  sig.disconnect(&foo);

下面的是模擬一個按照的操做,咱們定義了一個原型void(int x,int y),當咱們操做doOnClick時傳入符合的函數簽名時會進行鏈接,當調用 OnClick會操做綁定的方法 code

class Button
{
    typedef boost::signals2::signal<void (int x, int y)> OnClick;
public:
    typedef OnClick::slot_type OnClickSlotType;
    // 事件綁定,傳入一個事件自動進行關係,傳入的函數的定義OnClick;
    boost::signals2::connection doOnClick(const OnClickSlotType & slot);
     
    // 模擬用戶的點擊操做,輸入座標 52,38
    void simulateClick();
private:
    OnClick onClick;
};
 
boost::signals2::connection Button::doOnClick(const OnClickSlotType & slot)
{
    return onClick.connect(slot);
}
 
void Button::simulateClick()
{
    onClick(52, 38);
}
 
void printCoordinates(long x, long y)
{
    std::cout << "(" << x << ", " << y << ")\n";
}
 
//boost::signal<float (float,float),aggregate_values<vector<float>>>sig;
int main(int argc, const char * argv[]) {
    Button button;
    button.doOnClick(&printCoordinates);
    button.simulateClick();
}
相關文章
相關標籤/搜索