【cpp笔记-std::bind-占位符】

基本语法

std::bind 是 C++11 引入的一个功能强大的函数适配器,它能够将一个可调用对象(如函数、函数指针、成员函数、成员函数指针等)与其参数绑定起来,生成一个新的可调用对象。这个新的可调用对象在调用时可以自动传递预先绑定的参数。
基本用法
std::bind 的基本语法如下:

std::bind(fn, args...);

其中,fn 是一个可调用对象,args… 是传递给 fn 的参数列表。这些参数可以是具体的值,也可以是占位符(如 _1、_2 等),占位符表示在调用绑定后的函数时传递的参数。
举例说明

  1. 绑定普通函数
    假设我们有一个简单的加法函数:
int add(int a, int b) {
    return a + b;
}

我们可以使用 std::bind 将其中一个参数绑定为固定值:
auto add_five = std::bind(add, 5, std::placeholders::_1);
int result = add_five(3); // 等价于 add(5, 3),结果为 8
在这个例子中,add_five 是一个新的可调用对象,它将 add 函数的第一个参数绑定为 5,第二个参数使用占位符 _1 表示,这样在调用 add_five 时,只需要提供一个参数即可。
2. 绑定成员函数
假设我们有一个简单的类 Person,其中有一个成员函数 sayHello:

class Person {
public:
    void sayHello(const std::string& name) {
        std::cout << "Hello, " << name << "!" << std::endl;
    }
};

我们可以使用 std::bind 将 sayHello 成员函数绑定到一个具体的对象上:

Person person;
auto hello = std::bind(&Person::sayHello, &person, std::placeholders::_1);
hello("World");  // 输出 "Hello, World!"

在这个例子中,hello 是一个新的可调用对象,它将 Person::sayHello 成员函数绑定到 person 对象上,并使用占位符 _1 表示在调用时传递的参数。
3. 绑定引用参数
在C++中,std::bind 可以绑定引用参数,但需要注意一些细节。当你使用 std::bind 绑定引用参数时,你必须确保在绑定的可调用对象存在的整个生命周期内,所引用的对象也是有效的。否则,如果引用的对象在可调用对象之前被销毁,那么调用该对象将导致未定义行为。
绑定引用参数通常有两种方法:

  1. 直接使用引用类型作为 std::bind 的参数类型。
  2. 使用 std::ref 或 std::cref 包装器来包装引用。
    使用引用类型
    当你直接将引用类型作为 std::bind 的参数时,std::bind 会自动推断出你想要绑定一个引用。然而,这种方法在某些情况下可能不起作用,特别是当参数是通过模板或自动类型推导传递时。
    使用 std::ref 或 std::cref
    更可靠的方法是使用 std::ref(对于非const引用)或 std::cref(对于const引用)来明确地指定你想要绑定一个引用。这些函数模板返回一个特殊的引用包装器,它告诉 std::bind 保持对参数的引用,而不是复制它。
    下面是一个使用 std::ref 的例子:
#include <iostream>
#include <functional>

void print_sum(int a, int& b) {
    b += a;
    std::cout << "Sum: " << b << std::endl;
}

int main() {
    int value = 5;
    // 使用 std::ref 绑定引用参数
    auto bound_print_sum = std::bind(print_sum, 3, std::ref(value));
    
    // 在调用 bound_print_sum 之前,value 的值为 5
    bound_print_sum();  // 输出 "Sum: 8",并且现在 value 的值被修改为 8
    std::cout << "Value after call: " << value << std::endl;  // 输出 "Value after call: 8"
    
    return 0;
}

在这个例子中,print_sum 函数接受一个整数值和一个整数引用。我们使用 std::ref 来绑定 value 的引用到 print_sum 函数的第二个参数。当调用 bound_print_sum 时,它实际上调用了 print_sum(3, value),并且 value 被修改为 8。
请注意,如果你不使用 std::ref 或 std::cref,std::bind 将会尝试复制参数,这对于引用类型来说是不可能的,因此会导致编译错误。使用这些包装器是告诉 std::bind 你想要传递引用而不是值的重要方式。
注意事项

  • std::bind 可以用于延迟计算(Lazy Evaluation),即在需要时才进行计算。
  • std::bind 返回的可调用对象可以存储起来,并在需要时调用。
  • 使用 std::bind 时需要注意占位符的正确使用,以及参数类型的匹配。
  • 在 C++14 及以后的版本中,推荐使用泛型 lambda 表达式来替代 std::bind,因为 lambda 表达式更加灵活和易于理解。

占位符

占位符是 std::bind 的一个重要特性。它们允许你创建部分应用函数(partially applied functions)。这意味着你可以为某些参数提供值,而将其他参数留空,留待以后提供。在上文中占位符(如 _1、_2 等)是特殊的对象,用于表示当绑定对象被调用时应该从哪里获取参数。这些占位符是定义在 std::placeholders 命名空间中的。每一个占位符对应一个位置,_1 对应第一个位置,_2 对应第二个位置,依此类推。

当你使用 std::bind 创建一个新的可调用对象时,你可以将原始函数的某些参数绑定到具体的值上,而对于那些你希望在调用时才提供的参数,你可以使用占位符来代替。

例如,考虑一个简单的函数,它接受三个参数并返回它们的和:

int sum(int a, int b, int c) {
    return a + b + c;
}

如果你想创建一个新的函数对象,它固定第一个参数为 1,第二个参数为 2,但第三个参数在调用时才提供,你可以这样做:

auto partial_sum = std::bind(sum, 1, 2, std::placeholders::_1);
int result = partial_sum(3);  // 这将调用 sum(1, 2, 3) 并返回 6

然而,在这个特定的例子中,使用 _1 实际上是不必要的,因为 std::bind 会自动将未绑定的参数传递给原始函数。但如果你想重新排列参数的顺序,占位符就非常有用了:

auto rearranged_sum = std::bind(sum, std::placeholders::_3, std::placeholders::_1, std::placeholders::_2);
int another_result = rearranged_sum(1, 2, 3);  // 这将调用 sum(3, 1, 2) 并返回 6

在这个例子中,rearranged_sum 将第三个参数传递给 sum 的第一个参数,将第一个参数传递给 sum 的第二个参数,将第二个参数传递给 sum 的第三个参数。这就是占位符在 std::bind 中的用途:它们允许你控制参数在绑定函数和原始函数之间的映射关系。

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈喽汽车人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值