C++11 std::function及std::bind用法

发布时间 2023-03-30 21:39:11作者: _Explosion!

类似于c语言中的函数指针,C++11中,提供了一个通用的描述方法,就是std::function。 std::function可以hold住任何可以通过“()”来调用的对象,包括:

  • 普通函数
  • 成员函数
  • lambda
  • std::bind

std::function的语法格式为:

template <class Ret, class... Args> class function<Ret(Args...)>;

先看一个简单的例子

void printNumber(vector<int>& number, function<bool (int)> filter) {
    for (const int& i : number) {
        if (filter(i)) {
            cout<<i<<endl;
        }
    }
}

我们定义了一个printNumber函数,该函数有两个参数,一个是数组,一个是由std::function包装的---返回值为bool,参数为int的函数filter。

函数filter对传入数组number的每个成员进行操作并返回结果进行判断,那么该函数就可以通过改变filter的内容来实现各种不同的操作,如:

1 printNumber(numbers, [] (int i){ return i % 5 == 0;});
2 printNumber(numbers, [] (int i){ return i > 20;});

第一行函数打印数组中 模5==0 的所有成员,而第二行函数打印数组中 >20 的所有成员。

这样利用std::function便能快速简洁的完成一些操作内容有重复的操作,而不用再去重复声明函数。

当然std::function的功能还有许多,如可以通过闭包将函数中内的内容传递出去,如:

void getMinMax(vector<int>& number, function<void ()>& printer) {
    int min = number.front();
    int max = number.front();
    for (int i : number) {
        if (i < min) {
            min = i;
        }
        if (i > max) {
            max = i;
        }
    }
    printer = [=] () {
      cout << "min:" <<min<< endl;
      cout << "max:" << max << endl;
    };
}

上例中我们构造了一个getMinMax函数,该函数找到参数数组number的最大值和最小值,并且对参数printer进行赋值,使其拥有了打印number最大值最小值的功能。

一般来说min和max两个局部变量在函数结束离开其作用域后便会释放,而printer捕获了这两个值,从而使得在之后的程序中调用printer便能打印出min和max。


 

在写程序的过程中,我们有时候无法预料到函数传入的参数到底是什么,而std::bind可以将调用函数时的部分参数先制定好,留下一部分在真正调用时确定。

std::bind的语法格式为:

template<class Fn, class... Args> bind (Fn&& fn, Args&&... args);

有如下例子:

bool isTrue(int i,int min,int max){ return i>=min&&i<=max;}

假设我们仍用上面写过的函数printNumber,现在我们想用这个函数打印出 满足函数 bool isTrue(int i,int min,int max) 的所有数组成员。显然之前的std::function模板无法支持isTrue函数,

因此我们需要用到std::bind去绑定isTrue函数让其支持filter函数格式。假设我们现在需要打印出>=20并且<=50的成员。

std::bind(isTrue, placeholders::_1, 20, 50);
function<bool(int)> filter = std::bind(isBetween, placeholders::_1, 20, 40);
printNumber(numbers, filter);

placeholders::_1 的意思是,这里是一个占位符,在调用的时候,将实际传递的第一个参数放到这里。
占位符的数量可以是任意多的,像这样:
std::placeholders::_1, std::placeholders::_2, …, std::placeholders::_N。

有时候我们在调用一些回调函数的时候,若该函数是类成员函数,我们不希望使用虚函数时,可以结合std::function和std::bind来实现回调。

class Printer {
private:
    int min, max;
public:
    Printer(int x, int y) {
        min = x;
        max = y;
    }
    
    void print() {
        cout << "min:" << min << endl;
        cout << "max:" << max << endl;
    }
};

此处给出一个Printer类,假设我们需要调用其成员函数print

void usingCallback(function<void ()> print) {
    print();
}

我们可以通过下面的方法来调用print函数

Printer printer = Printer(10, 50);
function<void ()> cb = bind(&Printer::print, printer);
usingCallback(cb);

此处需注意,在绑定成员函数时,参数还需要一个类指针,因为成员函数参数默认均有一个this指针。

 

参考文章https://paul.pub/cpp-lambda-function-bind/