C++八股——函数对象、Lambda、bind、function

一、仿函数

仿函数:重载了操作符()的类,也叫函数对象

特征:可以有状态,通过类的成员变量来存储;(有状态的函数对象称之为闭包

样例

class Add {
public:
    void operator() (int count) {
        i += count;
        cout << "i:" << i << endl;
    }
    
    int operator() (int a, int b) {
        return a + b;
    }
    
    int i = 0; // 状态
};

二、Lambda表达式

Lambda表达式是一种方便创建匿名函数的语法糖,简化函数对象的创建,常用于需要短小逻辑的场景(如 STL 算法)。

语法

[捕获列表](参数列表) mutable -> 返回类型 { 函数体 }

  • 捕获列表:定义如何捕获外部变量,本质是将外部变量转变为类的成员变量
    • [=]:值捕获所有外部变量,只可读,不能修改
    • [&]:引用捕获所有外部变量,可读可写
    • [a, &b]:显示指定,值捕获a,引用捕获b
  • mutable:加上此关键字,允许修改值捕获的变量(值捕获的外部变量成为函数的状态,并不会改变实际的外部变量值)
  • 返回值类型:由于有类型推导,所以可以省略

底层原理

编译器将 lambda 转换为一个仿函数,重载 operator()。例如:

/*
int i = 0;
auto func = [i](int count) mutable -> void {
    i++;
    cout << "count:" << count << " i:" << i << endl;
};
*/
class LambdaFun {
public:
    LambdaFun(int _i) : i(_i) {}
    void operator() (int count) {
        i++;
    	cout << "count:" << count << " i:" << i << endl;
    }
private:
    int i;
};

例子

std::vector<int> nums = {3, 1, 4};
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; });
// 降序排序

三、bind

std::bind是用来通过绑定可调用对象以及参数生成新的可调用对象,支持参数顺序调整和部分参数绑定。

用法

#include <functional>
auto new_callable = std::bind(原函数, 绑定参数列表);
  • 占位符std::placeholders::_1, _2, ... 表示未绑定的参数位置

底层原理

编译器将 bind 转换为一个仿函数,重载 operator()。例如:

// auto f = std::bind(add, 10, 20);
class BindFun {
public:
    BindFun(function<int(int, int)> _fn, int _a, int _b) : fn(_fn), a(_a), b(_b) {}
    int operator()() const {
        return fn(a, b);
    }
private:
    function<int(int, int)> fn;
    int a, b;
};

// auto f = std::bind(&Add::add, &tmp, 10, std::placeholders::_1);
class BindCFun {
public:
    // 此处定义了一个类型别名Fn为指向Add类中参数为(int, int),返回值为int的成员函数的指针
    typedef int (Add::*Fn)(int, int);
    BindCFun(Fn _fn, Add *_c, int _a) : fn(_fn), c(_c), a(_a) {}
    int operator()(int b) const {
        return (c->*fn)(a, b);
    }
private:
    Fn fn;
    Add *c;
    int a;
};

样例

  • 绑定普通函数

    int add(int a, int b) {
        return a + b; 
    }
    auto f = std::bind(add, 10, std::placeholders::_1);
    int c = f(20); // c = 30
    
  • 绑定类成员函数

    class Add {
    public:
        int add(int a, int b) {
            return a + b;
        }
    };
    Add tmp;
    auto f = std::bind(&Add::add, &tmp, 10, std::placeholders::_1);
    int c = f(20) // c = 30
    

四、function

std::function是一个抽象了函数参数和返回值的类模板(多态函数包装器)。

用途

把任意函数包装成一个对象,该对象可以保存、传递、复制。

其可以包装:普通函数、类的成员函数和静态成员函数、仿函数、lambda表达式、bind返回的函数对象。

头文件:<functional>

用法:std::function<返回值类型(参数类型列表)> func;

样例

  1. 包装普通函数:

    #include <functional>
    
    int add(int a, int b) {
        return a + b;
    }
    
    // 包装普通函数
    std::function<int(int, int)> f_add = add; // f_add1 = &add 效果一样
    int c = f_add(1, 2); // c = 3
    
  2. 包装类静态成员函数:

    class StaticFunc {
    public:
        static int add(int a, int b) {
            return a + b;
        }
    };
    
    // 包装类静态成员函数
    std::function<int(int, int)> f_add = &StaticFunc::hello;
    int c = f_add(1, 2); // c = 3
    
  3. 包装态成员函数:

    class Add {
    public:
        int add(int a, int b) {
            return a + b;
        }
    };
    
    // 包装类成员函数
    std::function<int(Add *, int, int)> f_add = &Add::hello;
    Add tmp;
    int c = f_add(&tmp, 1, 2); // c = 3
    
  4. 包装仿函数:

    // 包装一中的仿函数Add
    std::function<void(int)> f_add1 = Add();
    std::function<int(int, int)> f_add2 = Add();
    f_add1(1); // 打印 i:1
    f_add1(2); // 打印 i:3, 因为仿函数保存了状态i的值
    int c = f_add2(1, 2); // c = 3
    
  5. 包装Lambda:

    int i = 0;
    auto func = [i](int count) mutable -> void {
        i++;
        cout << "count:" << count << " i:" << i << endl;
    };
    // auto 实际为编译器生成的匿名类型(非 std::function)
    // 等效的 std::function 类型为 std::function<void(int)>
    
    func(1); // 打印 count:1 i:1
    func(1); // 打印 count:1 i:2
    cout << i << endl; // 打印 0, 因为mutable关键字,所以不会修改外部变量实际的值
    
  6. 包装bind绑定的可调用对象

    三中的样例auto可显示转换为:std::function<int(int)>


总结C++11中function、Lambda、bind之间的关系

function用来描述函数对象的类型;Lambda表达式用来生成函数对象(可以访问外部变量的匿名函数);bind也是用来生成函数对象(函数和参数进行绑定的形式生成)

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值