1. 程式人生 > >C++11 std::function和std::bind繫結器

C++11 std::function和std::bind繫結器

前言

C++11增加了std::function和std::bind,使得使用標準庫函式時變得方便,而且還能方便地實現延遲求值。C++中,存在“可呼叫物件”這麼一個概念。準確來說,可呼叫物件有如下的定義:

(1)是一個函式指標

(2)是一個具有operator()成員函式的類物件(仿函式)

(3)是一個可被轉換為函式指標的類物件

(4)是一個類成員(函式)指標

1. std::function

std::function是可呼叫物件的包裝器。它是一個類模板,可以容乃除了類成員(函式)指標之外的所有可呼叫物件。通過制定它的模板引數,他可以用統一的方式處理函式、函式物件、函式指標,並允許儲存和延遲執行他們。


1.1 std::function的基本用法

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <functional>   //std::function

using std::cout;
using std::endl;

void func(int a, int b)     //普通函式
{
    cout << __FUNCTION__ << "(" << (a+b) << ")" << endl;
}

class A
{
public:
    static int class_func(int x)  //靜態成員函式
    {
        cout << __FUNCTION__ << "(" << x << ")" << endl;
        return x;
    }
};

class B
{
public:
    int operator()(int x)   //仿函式
    {
        cout << __FUNCTION__ << "(" << x << ")" << endl;
        return x;
    }
};

int main()
{
    //普通函式
    std::function<void(int, int)> func1 = func;
    func1(1000, 24);

    //類的靜態成員函式
    std::function<int(int)> func2 = A::class_func;
    cout << func2(2048) << endl;

    //仿函式
    B m_b;
    std::function<int(int)> func3 = m_b;
    cout << func3(4096) << endl;

    return 0;
}

當給定std::function填入合適的函式名之後,它就變成了可以容乃所有這一類呼叫方式的“函式包裝器”。

1.2 std::function作為回撥函式

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <functional>   //std::function

using std::cout;
using std::endl;

class A
{
public:
    A(const std::function<int(int)>& func):f_callback(func)
    {}
private:
    std::function<int(int)> f_callback;

public:
    void notify(int num)  //靜態成員函式
    {
        cout << __FUNCTION__ << "(" << f_callback(num) << ")" << endl;
    }
};

class B
{
public:
    int operator()(int x)   //仿函式
    {
        cout << __FUNCTION__ << "(" << x*2 << ")" << endl;
        return x;
    }
};

int main()
{
    //仿函式
    B m_b;
    A m_a(m_b);
    m_a.notify(1024);

    return 0;
}

在上面的例子中std::function可以取代函式指標的作用。因為它可以儲存函式延遲執行,所以比較適合作為回撥函式,也可以把它看做類似於C#中特殊的託管。

1.3 std::function作為函式引數

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <functional>   //std::function

using std::cout;
using std::endl;

void func(int a, int b)     //普通函式
{
    cout << __FUNCTION__ << "(" << (a+b) << ")" << endl;
}

void call_func(int x, int y, std::function<void(int, int)>& f)
{
    f(x, y);
}

int main()
{
    std::function<void(int, int)> func1 = func;
    call_func(1024, 96, func1);

    return 0;
}

2. std::bind繫結器

std::bind用來將可呼叫物件與其引數進行繫結。繫結之後的結果可以使用std::function進行儲存,並延遲呼叫到任何需要的時候。一般來講,它主要有兩大作用:

(1)將可呼叫物件與其引數一起繫結成為一個仿函式

(2)將多元可呼叫物件轉換成為1元或是(n-1)元呼叫物件,既只是繫結部分引數

2.1 std::bind基本用法

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <functional>   //std::function

using std::cout;
using std::endl;

void func(int a, int b)     //普通函式
{
    cout << __FUNCTION__ << "(" << (a+b) << ")" << endl;
}

void call_func(int x, int y, const std::function<void(int, int)>& f)
{
    f(x, y);
}

int main()
{
    auto func2 = std::bind(func, std::placeholders::_1, std::placeholders::_2);
    call_func(1024, 96, func2);

    return 0;
}
實際上std::bind的返回型別是一個stl內部定義的仿函式型別,在這裡就只需要知道它是一個仿函式,可以賦值給一個std::function,這裡直接用std::function型別來儲存std::bind的返回值也是可以的。

其中std::placeholders::_1是一個佔位符,代表這個文職將在函式呼叫時,被傳入的第一個引數代替。