C++ function与bind

std::function:

  • 可调用对象:
     是一个函数指针
     是一个具有 operator()成员函数的类对象(传说中的仿函数),lambda 表达式
     是一个可被转换为函数指针的类对象
     是一个类成员(函数)指针
     bind 表达式或其它函数对象

  • 而 std::function 就是上面这种可调用对象的封装器,可以把 std::function 看做一个函数对象,用于表示函数这个抽象概念。

  • std::function 的实例可以存储、复制和调用任何可调用对象,存储的可调用对象称为 std::function 的目标

  • 若 std::function 不含目标,则称它为空,调用空的 std::function 的目标会抛出 std::bad_function_call 异常。

  • std::function常用于函数回调

#include <iostream>
#include <functional>
using namespace std;

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const{
        cout << num_ + i << endl;
    }
    int num_;
};

struct PrintNum {
    void operator()(int i) const {
        cout << i << "\n";
    }
};

void print_num(int i) {
    cout << i << "\n";
}

int main() {
    // 存储自由函数
    std::function<void(int)> f_display = print_num;
    f_display(-9);

    // 存储lambda
    std::function<void()> f_display_42 = []() { print_num(42); };
    f_display_42();

    // 存储到 std::bind 调用结果
    std::function<void()> f_display_31337 = std::bind(print_num, 31337);
    f_display_31337();

    // 存储成员函数的调用
    std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
    const Foo foo(314159);
    f_add_display(foo, 1);
    f_add_display(314159, 1);

    // 存储类数据成员访问器的调用
    std::function<int(Foo const&)> f_num = &Foo::num_;
    cout << "num_: " << f_num(foo) << endl;

    // 存储成员函数及对象的调用
    using std::placeholders::_1;
    std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
    f_add_display2(2);

    // 存储数据成员函数和对象指针的调用
    std::function<void(int)>f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
    f_add_display3(3);
    
    // 存储到函数对象的调用
    std::function<void(int)> f_add_display_obj = PrintNum();
    f_add_display_obj(18);

    return 0;
}

std::bind:

  • 使用 std::bind 可以将可调用对象和参数一起绑定,绑定后的结果使用 std::function 进行保存,并延迟调用到任何我们需要的时候。*

  • std::bind 通常有两大作用:*

    • 可调用对象与参数一起绑定为另一个 std::function 供调用*

    • 将 n 元可调用对象转成 m(m < n)元可调用对象,绑定一部分参数,这里需要使用 std::placeholders*

#include <iostream>
#include <functional>
#include <memory>
using namespace std;

struct Foo {
    void print_sum(int n1, int n2) {
        cout << n1 + n2 << endl;
    }
    int data = 10;
};

void f(int n1, int n2, int n3, const int& n4, int n5) {
    cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << endl;
}

int g(int n) { return 0; }


int main() {
     // 针对 _1, _2, _3... 用作参数占位,延时输入参数
    using namespace std::placeholders;

    // 演示参数重排序和按引用传递
    int n = 7;

    // (_1 与 _2 来自 std::placeholders, 并表示将来会传递给 f1 参数)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    // 1 为 _1 所绑定,2 为 _2 所绑定,不使用 1001
    // 进行到 f(2, 42, 1, n, 7)
    f1(1, 2, 1001);  

    // 嵌套 bind 子表达式共享占位符
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    // 进行到 f(12, g(12), 12, 4, 5); 的调用
    f2(10, 11, 12);  

    // 绑定指向成员函数指针
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);

    // 绑定指向数据成员指针
    auto f4 = std::bind(&Foo::data, _1);
    cout << f4(foo) << endl;
    // 智能指针亦能用于调用被引用对象的成员
    cout << f4(std::make_shared<Foo>(foo)) << endl;

    return 0;
}
posted @ 2023-10-19 08:48  洋綮  阅读(10)  评论(0)    收藏  举报