boost::functionとboost::bind用法詳細

8117 ワード

本文boost::function部分から:https://blog.csdn.net/huangjh2017/article/details/71124827
boost::bind部分から:https://yq.aliyun.com/articles/33187
boost::function
は関数オブジェクトのコンテナであり、C/C++の関数ポインタタイプの一般化のように概念的に「スマート関数ポインタ」である.元の関数ポインタまたは関数オブジェクトをオブジェクトとしてカプセル化し、関数署名に一致する任意の呼び出し可能なオブジェクトを収容できます.したがって、コールバックメカニズムに使用され、関数または関数オブジェクトを一時的に保管し、その後に必要なタイミングでコールバックメカニズムをより弾力性のあるものにすることができる.
boost::functionがコールバックメカニズムによく使われている以上、まずコールバック関数とは何かを見てみましょう.
コールバック関数は、関数ポインタによって呼び出される関数です.関数のポインタ(アドレス)をパラメータとして別の関数に渡すと、そのポインタが指す関数を呼び出すために使用される場合、これはコールバック関数です.コールバック関数は、関数の実装者によって直接呼び出されるのではなく、特定のイベントまたはアイテムが発生したときに別の側によって呼び出され、イベントまたは条件に応答するために使用されます.
まず、c/c++における関数ポインタの一般関数とクラスメンバー関数の使用を見てみましょう.
#include 
 
using namespace std;
 
class CEventQuery;
 
typedef bool (*CommonFuncPoint)(void);                //      
typedef bool (CEventQuery::*ClassFuncPoint)(int);    //       
 
bool CommonFunc(void)
{
    //       ,           
    //   ,    。
    cout << "CallBackFunc Common Function Call!" << endl;
    //                    
    //....
    return true;
}
 
class CEventQuery
{
public:
    CEventQuery(CommonFuncPoint eventFunc)
        :m_Event(eventFunc)
    {
    
    }
 
    ~CEventQuery()
    {
    
    }
 
    void Query(void)
    {
        //                       
        //                   ,         
        m_Event();
    }
 
    bool DoSomething(int iValue)
    {
        cout << "Class Function DoSomething Parament : " << iValue << endl;
        return true;
    }
 
private:
    CommonFuncPoint m_Event;
};
 
int main(void)
{
    CEventQuery tEventQuery(CommonFunc);
 
    tEventQuery.Query();
 
    ClassFuncPoint ClassFunc1 = &CEventQuery::DoSomething;
    (tEventQuery.*ClassFunc1)(10);
 
    tEventQuery.DoSomething(20);
 
    return 0;
}

実行結果は次のとおりです.
CallBackFunc Common Function Call!
Class Function DoSomething Parament : 10
Class Function DoSomething Parament : 20

不十分な点は,この方式の呼び出しは関数ポインタにのみ適用され,非関数ポインタ(例えば関数オブジェクト)には適用されないことである.これが限界である.
以前に関数ポインタを使用したのとは異なり、functionは関数のコンテナのようなものであり、functionを汎化された関数ポインタとして想像することもできます.それは、宣言された関数タイプ、一般的な関数、メンバー関数、関数オブジェクトがfunctionイメージに格納され、必要に応じて呼び出されます.
boost::functionは関数ポインタの代わりに機能し、関数や関数オブジェクトを受け入れることができ、プログラムの柔軟性を高めることができます.もちろん、メリットをもたらすと同時に、必然的に弊害もあります.boost::functionは関数ポインタより体積がやや大きく、速度がやや遅い.しかしboost::functionがもたらす柔軟性に比べて、速度と体積は重要です.
Boostの公式ドキュメントを参照してください.Boost.Functionには2つの形式があります.優先形式と携帯形式です.文法は次のとおりです.
優先構文ポータブル構文
boost::function
 f;
boost::function2
 f;

この2つの形式は等価で、自分の好きな形式を選ぶことができます(古いコンパイラでは携帯型をサポートしていないものもあります).例として、一般関数、クラスメンバー関数、関数オブジェクトの使用を示します.もちろんfunctionはbindと組み合わせて使用することができ、bind式の結果を格納し、bindを複数回呼び出すことができる.今のところ使っていないので、今度補充します.
#include 
#include 
 
using namespace std;
 
template
class CFuncDemo
{
public:
    CFuncDemo(int iValue)
        :m_iValue(iValue)
    {
    }
 
    template
    void acceptFunc(CallBackFunc Func)
    {
        m_Func = Func;
    }
 
    void CommonResult()
    {
        m_Func(m_iValue);
    }
 
    template
    void ClassMemberResult(T &t)
    {
        m_Func(t, m_iValue);
    }
 
    void FuncObjResult()
    {
        m_Func(m_iValue);
    }
 
private:
    Func m_Func;
    int m_iValue;
};
 
//    
void CommonFunc(int iValue)
{
    cout << "CallBack Common Function" << endl;
    cout << "2 * iValue = " << 2 * iValue << endl;
}
 
//                
class CMultiple
{
public:
    void ClassFunc(int iValue)
    {
        cout << "CallBack Class Member Function" << endl;
        cout << "3 * iValue = " << 3 * iValue << endl;
    }
};
 
//                  
class CFuncObj
{
public:
    void operator()(int iValue)
    {
        cout << "CallBack Function Object" << endl;
        cout << "4 * iValue = " << 4 * iValue << endl;
    }
};
 
int main(void)
{
    //         ,       :    、     、       
 
    //    
    CFuncDemo<:function>> tFuncCommon(10);
    tFuncCommon.acceptFunc(CommonFunc);
    tFuncCommon.CommonResult();
 
    //     
    CMultiple tMember;
    CFuncDemo<:function int="">> tFuncClassMember(10);
    tFuncClassMember.acceptFunc(&CMultiple::ClassFunc);
    tFuncClassMember.ClassMemberResult(tMember);
 
    //    
    CFuncObj tObj;
    CFuncDemo<:function>> tFuncObj(10);
    //tFuncObj.acceptFunc(tObj);
    //function          ,  ref             
    tFuncObj.acceptFunc(boost::ref(tObj));
    tFuncObj.FuncObjResult();
 
    return 0;
}

テスト結果は次のとおりです.
CallBack Common Function
2 * iValue = 20
CallBack Class Member Function
3 * iValue = 30
CallBack Function Object
4 * iValue = 40

boost::bind
#include 
#include 
#include 
 
using namespace boost;
using namespace std;
 
int f(int a, int b)
{
    return a + b;
}
 
int g(int a, int b, int c)
{
    return a + b * c;
}
 
class Point
{
public:
    Point(int x, int y) : _x(x), _y(y) {}
    void print(const char *msg) {
        cout << msg << "x=" << _x << ", y=" << _y << endl;
    }
private:
    int _x, _y;
};
 
int main()
{
    //! f       ,f           。      ,    
    cout << bind(f, 2, 3)() << endl;    // ==> f(2, 3)
    cout << bind(f, 12, _1) (5) << endl;   // ==> f(12, 5),    b      
    cout << bind(g, _2, _1, 3) (3, 5) << endl;  // ==> g(5, 3, 3)     
 
    Point p(11, 34);
    Point &rp = p;
    Point *pp = &p;
 
    bind(&Point::print, p, "Point: ") ();
    //   ^              ^
    //   ,   Point::print     ,        &  。
    //        、  、  
    bind(&Point::print, rp, "Reference: ") ();  //!   
    bind(&Point::print, pp, _1) ("Pointer: ");  //!   
    bind(&Point::print, _1, _2) (p, "As parameter: ");  //!              
 
    //! function             
    function func0 = bind(&Point::print, p, "func0: ");
    function func1 = bind(&Point::print, pp, _1);
 
    func0();    //! function     
    func1("func1: ");
 
    return 0;
}

一般的にbindはfunctionと組み合わせて使用されます.
bindとfunctionはまた、タイプの異なる関数(メンバー関数と非メンバー関数)を統合した関数呼び出しインタフェースにパッケージすることもできます.次の例を示します.
#include 
#include 
#include 
#include 
 
using namespace boost;
using namespace std;
 
class Point
{
public:
    Point(int x, int y) : _x(x), _y(y) {}
    void print(string msg) {
        cout << msg << "x=" << _x << ", y=" << _y << endl;
    }
private:
    int _x, _y;
};
 
class Person
{
public:
    Person(string name, int age) : _name(name), _age(age) {}
    void sayHello() {
        cout << "Hello, my name is " << _name << ", my age is : " << _age << endl;
    }
private:
    string _name;
    int _age;
};
 
void printSum(int limit)
{
    int sum = 0;
    for (int i = 0; i < limit; ++i) {
        sum += i;
    }
    cout << "sum = " << sum << endl;
}
 
void doAll(vector > &funcs)
{
    for (size_t i = 0; i < funcs.size(); ++i) {
        funcs[i] ();
    }
}
 
int main()
{
    vector > funcList;
 
    Person john("John", 23);
    funcList.push_back(bind(&Person::sayHello, john));
 
    Point p1(23, 19);
    funcList.push_back(bind(&Point::print, p1, "Point: "));
 
    funcList.push_back(bind(printSum, 20));
 
    doAll(funcList);
    return 0;
}