C++小利器之std::bind参数绑定包装器的使用详解

 更新时间:2023年12月22日 08:51:41   作者:ENG八戒  
从 C++11 开始,标准库提供了 std::bind 用于绑定函数 f 和调用参数,返回一个新可调用函数对象 fn,下面就跟随小编一起深入了解一下std::bind的具体使用吧

C++ 原生支持函数输入参数的默认值,但是有些业务场景下对原有设定的默认值不满意,那么可不可以临时改改?

请注意,随意改变原有代码逻辑,并不符合软件设计原则。有没有什么方案或者特性可以做到不修改原有代码逻辑,以实现新增参数默认值(或者在调用时绑定特性参数)的功能?

从 C++11 开始,标准库提供了 std::bind 用于绑定函数 f 和调用参数,返回一个新可调用函数对象 fn (也有喊它做仿函数的)。于是,在调用函数对象 fn 和输入新参数时,相当于调用了原来的函数 f 并自动按照绑定的关系映射参数,映射的方式非常灵活。这样被绑定映射的参数,实现原有函数 f 的参数新默认值功能,或者减少调用函数 f 时输入的参数个数等便捷需求。

简而言之,std::bind 被称为转发调用包装器。

绑定时,通过占位符 _1, _2, _3… ,指定在调用函数对象 fn 的输入参数和传递给函数 f 的参数之间的映射位置。

被绑定的函数 f 也分种类,那么,基于不同类型函数的应用示例是怎样的呢?

绑定静态或者全局函数

#include <functional>

void output1(int a)
{
    printf("%d\n", a);
}

void output2(int a, int b)
{
    printf("%d %d\n", a, b);
}

int main(int argc, char * argv[])
{
    auto fn1 = std::bind(output1, std::placeholders::_1);
    fn1(1);
    auto fn2 = std::bind(output2, std::placeholders::_2, 0);
    fn2(3, 2);
    return 0;
}

output:

1
2 0

占位符代表函数对象的输入参数,std::placeholders::_1 对应调用函数对象 fn 时的第 1 个输入参数,依次类推。

细心的你可能会留意 std::bind 返回的是可调用对象,这个和同样从 C++11 开始引入的 Lambda 表达式概念是类似的,那么有没有可能用 Lambda 表达式互相替换?试试改为使用 Lambda 表达式实现

int main(int argc, char * argv[])
{
    auto fn1 = [](int a) -> void {
        output1(a);
    };
    fn1(1);
    auto fn2 = [](int a, int b) -> void {
        output2(b, 0);
    };
    fn2(3, 2);
    return 0;
}

这样子替换后,执行输出结果是一样的。

output:

1
2 0

绑定对象成员函数

如果被绑定的函数是对象成员,需要指定所属对象,看代码

#include <functional>

class A
{
public:
    void output(int a, int b)
    {
        printf("%d %d\n", a, b);
    }
};

int main(int argc, char * argv[])
{
    A obj;
    auto fn = std::bind(&A::output, &obj, std::placeholders::_2, std::placeholders::_1);
    fn(5, 3);
    return 0;
}

output:

3 5

用 Lambda 表达式替换试试

int main(int argc, char * argv[])
{
    A obj;
    auto fn = [&obj](int a, int b) -> void {
        obj.output(b, a);
    };
    fn(5, 3);
    return 0;
}

output:

3 5

Notice:绑定的时候需要指定上下文环境(实例对象),这种场景已经涉及到闭包的概念了。由于上下文环境是有生命周期的,比如上面用到的实例对象 a,如果在超出了其生命周期的情况下,引用其内部已被释放的资源,是会引起程序执行异常的,这里提醒一下。

平替 Lambda

以上面两种场景示例代码的比较,在参数绑定的场景下,为了达到相同效果,Lambda 表达式的书写略显罗嗦,而 std::bind 的格式更有函数式编程的味道,可见,某些场景下推荐 std::bind 替代 Lambda 表达式。

能不能平替也分场景,三思而行。

到此这篇关于C++小利器之std::bind参数绑定包装器的使用详解的文章就介绍到这了,更多相关C++ std::bind内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用Matlab复刻举牌加油小人生成器

    利用Matlab复刻举牌加油小人生成器

    upuptoyou是一款非常有创意的小工具,可以在线生成举牌小人,看起来很可爱,也比较有趣,并能用于表白,或节日送祝福等场景。本文将用Matlab复刻这一小工具,需要的可以参考一下
    2022-03-03
  • C语言报错:Undefined Reference的产生原因和解决方案

    C语言报错:Undefined Reference的产生原因和解决方案

    Undefined Reference(未定义引用)是C语言编译过程中常见的错误之一,通常在链接阶段出现,本文将详细介绍Undefined Reference的产生原因,提供多种解决方案,并通过实例代码演示如何有效避免和解决此类错误,需要的朋友可以参考下
    2024-06-06
  • C语言重难点之内存对齐和位段

    C语言重难点之内存对齐和位段

    这篇文章主要介绍了C语言重难点之内存对齐和位段,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • C++使用OpenCV进行物体识别与检测的三种方法

    C++使用OpenCV进行物体识别与检测的三种方法

    物体识别与检测是计算机视觉中的核心任务之一,它被广泛应用于自动驾驶、安防监控、图像分析等领域,通过物体检测技术,计算机能够从图像中识别出特定的物体或目标,本文将介绍如何使用 C++ 和 OpenCV 库进行物体识别与检测,需要的朋友可以参考下
    2025-04-04
  • C++中关于委派(Delegates)的实现示例

    C++中关于委派(Delegates)的实现示例

    这篇文章主要介绍了C++中关于委派(Delegates)的实现示例,针对C++11的一些新特性进行讲解,需要的朋友可以参考下
    2015-07-07
  • C++为什么不能修改set里的值?非要修改怎么办?

    C++为什么不能修改set里的值?非要修改怎么办?

    因为之前的文章有说过C++中 set的介绍及用法,今天这篇文章我们就来说说C++为什么不能修改set里的值,如果非要修改的话应该怎么办,下面我们一起进入文章看看下面内容,需要的朋友可以参考以下,希望对你有所帮助
    2021-11-11
  • 深入解析C++中的std::thread的使用

    深入解析C++中的std::thread的使用

    这篇文章主要介绍了C++中的std::thread的使用,在C++11新标准中,可以简单通过使用thread库,来管理多线程,本文通过实例代码给大家详细讲解,需要的朋友可以参考下
    2023-04-04
  • C++使用easyX库实现三星环绕效果流程详解

    C++使用easyX库实现三星环绕效果流程详解

    EasyX是针对C/C++的图形库,可以帮助使用C/C++语言的程序员快速上手图形和游戏编程。这篇文章主要介绍了C++使用easyX库实现三星环绕效果,需要的可以参考一下
    2022-10-10
  • C语言中的文件操作详解

    C语言中的文件操作详解

    这篇文章主要介绍了C语言中的文件操作详解,使用文件可以将数据直接存放到电脑的硬盘上,做到了数据的持久化
    2022-07-07
  • C++中异常处理的基本思想及throw语句抛出异常的使用

    C++中异常处理的基本思想及throw语句抛出异常的使用

    这篇文章主要介绍了C++中异常处理的基本思想及throw类抛出异常的使用,也深入谈到了异常被抛出后的栈解旋unwinding过程,需要的朋友可以参考下
    2016-03-03

最新评论