C++ 新特性 函数对象包装器 function 与 bind

函数对象包装器

1. std::function

Lambda 表达式的本质是一个函数对象,当 Lambda 表达式的捕获列表为空时,Lambda 表达式还能够作为一个函数指针进行传递,例如:

#include <iostream>

using foo = void(int); // 定义函数指针
void function(foo f) {
    f(1);
}

int main() {
    auto f = [](int value) {
        std::cout << value << std::endl;
    };

    function(f);
    f(1);
    return 0;
}

上面的代码给出了两种不同的调用形式,一种是将 Lambda 作为函数指针传递进行调用,而另一种则是直接调用 Lambda 表达式, 在 C++11 中,统一了这些概念,将能够被调用的对象的类型,统一称为可调用类型,而这种类型,便是通过 std::function 引入的。

C++11 std::function 是一种通用的、多态的函数封装,它的实例可以对任何可以调用的目标实体进行存储、复制和调用操作,它也是C++中现有的可调用实体的一种类型安全的包裹(相对来说,函数指针的调用不是类型安全的),换句话说,就是函数的容器。当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理,例如:

#include <iostream>
#include <functional>

int foo(int para) {
    return para;
}

int main() {
    // std::function 包装了一个返回值为 int, 参数为 int 的函数
    std::function<int(int)> func = foo;

    int important = 10;
    std::function<int(int)> func2 = [&](int value) -> int {
        return 1 + value + important;
    };
    std::cout << func(10) << endl;
    std::cout << func2(10) << endl;
}

2. std::bind/std::placeholder

std::bind 则是用来绑定函数调用的参数的,它解决的需求是我们有时候并不一定能够一次性获得调用某个函数的全部参数,通过这个函数,我们可以将部分调用参数体腔绑定到函数身上成为一个新的对象,然后再参数齐全后,完成调用。例如:

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

int test(int n) {
    cout << n << endl;
    return n;
}

class CTest {
public:
    int MyTest(int n) {
        cout << n << endl;
        return n;
    }

    // 仿函数
    int operator()(int n) {
        cout << n << endl;
        return n;
    }
};

void add(int a, int b, int c) {
    cout << a << " " << b << " " << c << endl;
}

int main() {
    // 函数对象包装器
    // 为函数提供了一种容器(封装)
    test(1);

    // 支持4中函数的封装
    // 1. 普通函数
    // 2. 匿名函数
    // 3. 类的成员函数
    // 4. 仿函数(重载了() 运算符的函数

    // 普通函数
    std::function<int(int)> f = test;

    // 匿名函数
    std::function<int(int)> f2 = [](int n) -> int {
        cout << n << endl;
        return n;
    };

    // 类的成员函数
    std::function<int(CTest*, int)> f3 = &CTest::MyTest;
    CTest t;
    f3(&t, 123);

    // 
    
    f(123);

    f2(1234);

    // 仿函数的调用
    t(123);
    std::function<int(CTest*, int)> f4 = &CTest::operator();
    f4(&t, 123);

    // bind 机制
    auto a = std::bind(add, 1, 2, 3);
    a();

    auto foo2 = std::bind(add, std::placeholders::_2, std::placeholders::_1, 3);
    foo2(1, 2); // 2 1 3
    return 0;

}
posted @ 2022-09-14 21:10  岁月飞扬  阅读(64)  评论(0编辑  收藏  举报