C++之std::function、std::bind、lambda特性

2024-04-15 13:41:40 浏览数 (2)

START

Hi,大家好!今天我们来说一说c 中std::function、std::bind、lambda等用法,这些用法使函数调用更加方便。

unsetunsetstd::functionunsetunset

std::function 是 C 11 标准库中的一个模板类,它可以用于包装任何可调用对象(函数、函数指针、成员函数、lambda 表达式等),并提供一种统一的方式来管理和调用这些可调用对象。

下面是 std::function 的主要特点和用法:

  1. 函数包装器std::function 可以包装各种可调用对象,包括函数、函数指针、成员函数指针、lambda 表达式等。
  2. 类型安全std::function 提供了类型安全的方式来管理可调用对象,编译器会在编译时检查参数和返回值的类型是否匹配。
  3. 灵活性std::function 可以在运行时决定要调用的具体函数或者函数对象,使得代码更加灵活。
  4. 可复制性std::function 对象是可复制的,可以像普通对象一样进行复制和赋值操作。

下面是 std::function 的基本用法示例:

代码语言:javascript复制
#include <iostream>
#include <functional>

// 函数对象类
class MyFunctionObject {
public:
    int operator()(int a, int b) const {
        return a   b;
    }
};

// 普通函数
int add(int a, int b) {
    return a   b;
}

int main() {
    // 使用函数对象
    MyFunctionObject myObject;
    std::function<int(int, int)> func1 = myObject;

    // 使用普通函数
    std::function<int(int, int)> func2 = add;

    // 使用 lambda 表达式
    std::function<int(int, int)> func3 = [](int a, int b) { return a   b; };

    std::cout << "Result 1: " << func1(1, 2) << std::endl;
    std::cout << "Result 2: " << func2(3, 4) << std::endl;
    std::cout << "Result 3: " << func3(5, 6) << std::endl;

    return 0;
}

在这个示例中,我们演示了如何使用 std::function 包装函数对象、普通函数和 lambda 表达式,并通过调用 std::function 对象来执行相应的操作。

unsetunsetstd::bindunsetunset

std::bind 是 C 11 标准库中的一个函数模板,用于创建一个可调用对象(函数对象或函数指针),并绑定到指定的参数。它可以用于延迟函数调用、部分应用函数、改变函数参数顺序等场景。

下面是 std::bind 的主要特点和用法:

  1. 延迟函数调用std::bind 允许我们在创建可调用对象时不立即调用函数,而是将函数对象和参数绑定起来,以便在稍后的时间点进行调用。
  2. 部分应用函数std::bind 允许我们在创建可调用对象时只绑定部分参数,剩余的参数可以在稍后的调用中提供,从而实现函数的部分应用。
  3. 改变函数参数顺序std::bind 允许我们改变函数的参数顺序,即将函数的某些参数按照指定的顺序重新排列。
  4. 支持占位符std::bind 支持占位符(std::placeholders::_1std::placeholders::_2 等),用于指示在调用时提供的参数的位置。

下面是 std::bind 的基本用法示例:

代码语言:javascript复制
#include <iostream>
#include <functional>

// 函数对象类
class MyFunctionObject {
public:
    int operator()(int a, int b, int c) const {
        return a   b   c;
    }
};

int main() {
    MyFunctionObject myObject;

    // 绑定函数对象和参数
    auto func1 = std::bind(myObject, 1, 2, 3);

    // 部分应用函数
    auto func2 = std::bind(myObject, std::placeholders::_1, 2, std::placeholders::_2);

    std::cout << "Result 1: " << func1() << std::endl; // 输出:6
    std::cout << "Result 2: " << func2(10, 20) << std::endl; // 输出:32

    return 0;
}

在这个示例中,我们使用 std::bind 将函数对象 myObject 绑定到参数,并创建了两个可调用对象 func1func2func1 绑定了完整的参数,而 func2 则只绑定了部分参数,剩余的参数在调用时提供。

unsetunsetlambdaunsetunset

Lambda 表达式是 C 11 引入的一种匿名函数语法,它可以方便地创建临时函数对象,用于在函数调用时作为参数传递或者作为局部函数使用。Lambda 表达式可以捕获外部变量,并具有与普通函数相似的语法结构。

Lambda 表达式的一般语法形式如下:

代码语言:javascript复制
[capture](parameters) -> return_type { body }

其中:

  • capture:捕获列表,用于指定 Lambda 表达式访问的外部变量。
  • parameters:参数列表,与普通函数的参数列表类似。
  • return_type:返回类型,可以省略,编译器会自动推导返回类型。
  • body:Lambda 函数体,与普通函数的函数体类似。

下面是一些 Lambda 表达式的常见用法:

无捕获、无参数、无返回值的 Lambda 表达式

代码语言:javascript复制
[]() { std::cout << "Hello, Lambda!" << std::endl; }

有捕获、有参数、有返回值的 Lambda 表达式

代码语言:javascript复制
int x = 10;
auto func = [x](int y) -> int { return x   y; };

Lambda 表达式作为函数对象传递

代码语言:javascript复制
std::vector<int> nums = {1, 2, 3, 4, 5};
int total = 0;
std::for_each(nums.begin(), nums.end(), [&total](int x) { total  = x; });

Lambda 表达式作为排序函数的比较器

代码语言:javascript复制
std::vector<int> nums = {5, 3, 1, 4, 2};
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a < b; });

Lambda 表达式捕获外部变量

代码语言:javascript复制
int x = 10;
auto func = [x](int y) { return x   y; };

Lambda 表达式的参数列表和返回类型的自动推导

代码语言:javascript复制
auto func = [](int x, int y) { return x   y; };

Lambda 表达式的默认捕获方式

代码语言:javascript复制
int x = 10;
auto func = [=](int y) { return x   y; }; // 默认以值方式捕获所有外部变量

Lambda 表达式的可变捕获

代码语言:javascript复制
int x = 10;
auto func = [x]() mutable { x  ; }; // 使用 mutable 关键字使捕获的变量可变

以上是 Lambda 表达式的一些常见用法示例,它们可以帮助简化代码,提高代码的可读性和可维护性。

0 人点赞