当前位置: 首页 > web >正文

C++23 std::bind_back:一种调用包装器 (P2387R3)

文章目录

    • 引言
    • 背景知识
      • 旧有的绑定工具
      • C++20的std::bind_front
    • std::bind_back的定义和功能
      • 定义
      • 功能
    • std::bind_back的使用场景
      • 简化回调函数
      • 部分应用参数
    • std::bind_back与其他绑定工具的对比
      • 与std::bind的对比
      • 与std::bind_front的对比
    • 总结

引言

在C++的发展历程中,每一个新标准的发布都会带来一些令人期待的新特性。C++23也不例外,其中std::bind_back就是一个非常实用的新特性。它是一种调用包装器,为开发者在处理函数调用和参数绑定时提供了更多的灵活性。本文将详细介绍std::bind_back的定义、功能、使用场景以及与其他相关工具的对比。

背景知识

在深入了解std::bind_back之前,我们需要先了解一些相关的背景知识。在C++中,函数对象和可调用对象是非常重要的概念。函数对象是重载了()运算符的类的实例,而可调用对象则是可以像函数一样被调用的对象,包括函数、函数指针、lambda表达式、bind对象等。

旧有的绑定工具

在C++11中引入了std::bind,它允许预设参数,创建新的函数对象。例如:

#include <functional>
#include <iostream>using namespace std::placeholders;double divMe(double a, double b) { return a / b; };int main()
{std::function<double(double, double)> myDiv1 = std::bind(divMe, _1, _2);std::function<double(double)> myDiv2 = std::bind(divMe, 2000, _1);std::cout << "myDiv1(1000, 5) = " << myDiv1(1000, 5) << std::endl; // 200std::cout << "myDiv2(10) = " << myDiv2(10) << std::endl; // 200return 0;
}

在这个例子中,std::bind将函数divMe与不同的参数进行绑定,创建了新的可调用对象。

C++20的std::bind_front

C++20引入了std::bind_front,它可以从可调用对象创建可调用包装器。调用std::bind_front(func, arg...)会将所有参数arg绑定到func的前面,并返回一个可调用包装器。例如:

std::function<double(double)> myDiv3 = std::bind_front(divMe, 2000);
std::cout << "myDiv3(5) = " << myDiv3(5) << std::endl; // 400

这里std::bind_front将参数2000绑定到divMe的前面,调用myDiv3(5)时相当于调用divMe(2000, 5)

std::bind_back的定义和功能

定义

std::bind_back是C++23中引入的一个函数模板,在标头<functional>中定义。其原型如下:

template < class F, class ... Args >
constexpr /*unspecified*/ bind_back( F&& f, Args&&... args );

它为f生成转发调用包装。调用此包装等价于绑定尾sizeof...(Args)个参数到args再调用f。换言之,std::bind_back (f, bound_args...) (call_args...) 等价于 std::invoke( f, call_args..., bound_args...)

功能

std::bind_back的主要功能是将参数绑定到可调用对象的后面,创建一个新的可调用包装器。这使得在某些场景下,我们可以更方便地处理函数调用和参数传递。例如:

std::function<double(double)> myDiv4 = std::bind_back(divMe, 10);
std::cout << "myDiv4(2000) = " << myDiv4(2000) << std::endl; // 200

在这个例子中,std::bind_back将参数10绑定到divMe的后面,调用myDiv4(2000)时相当于调用divMe(2000, 10)

std::bind_back的使用场景

简化回调函数

在很多异步编程场景下,常常需要传递一个不带参数的回调函数。std::bind_back可以让你将带参数的函数转换为无参数的形式,非常适合线程池、std::function<void()>回调等场景。例如:

#include <iostream>
#include <thread>
#include <functional>void task(int x, int y) {std::cout << "Task with values: " << x << " and " << y << std::endl;
}int main() {auto bound_task = std::bind_back(task, 42);std::thread t([&]() { bound_task(10); });t.join();return 0;
}

在这个例子中,std::bind_back将参数42绑定到task的后面,创建了一个新的可调用对象bound_task。然后将其封装在lambda表达式中传递给线程,调用时只需要提供剩余的参数10

部分应用参数

std::bind_back主要用于部分应用函数的参数。也就是说,您可以用std::bind_back预先绑定函数的一部分参数,然后在之后的调用中只提供其余参数。这使得代码更加灵活和模块化,尤其是当需要在不同的上下文中使用相同的函数但具有不同的部分参数时。例如:

#include <iostream>
#include <functional>int add(int a, int b, int c) {return a + b + c;
}int main() {auto partial_add = std::bind_back(add, 3, 4);std::cout << partial_add(2) << std::endl; // 9return 0;
}

在这个例子中,std::bind_back将参数34绑定到add的后面,创建了一个新的可调用对象partial_add。调用partial_add(2)时相当于调用add(2, 3, 4)

std::bind_back与其他绑定工具的对比

与std::bind的对比

  • 灵活性std::bind可以将参数绑定到任意位置,还可以改变参数的顺序,引入占位符等。而std::bind_back只能将参数绑定到可调用对象的后面。
  • 可读性std::bind的使用可能会导致代码变得晦涩难懂,尤其是在使用占位符时。而std::bind_back的语义更加明确,代码可读性更高。

与std::bind_front的对比

  • 绑定位置std::bind_front将参数绑定到可调用对象的前面,而std::bind_back将参数绑定到可调用对象的后面。这使得它们在不同的场景下有不同的用途。
  • 使用场景:当需要将参数绑定到前面时,使用std::bind_front;当需要将参数绑定到后面时,使用std::bind_back

总结

std::bind_back是C++23中一个非常实用的新特性,它为开发者在处理函数调用和参数绑定时提供了更多的灵活性。通过将参数绑定到可调用对象的后面,std::bind_back可以简化回调函数、部分应用参数等。与std::bindstd::bind_front相比,它具有自己独特的优势和适用场景。在实际开发中,我们可以根据具体的需求选择合适的绑定工具。

http://www.xdnf.cn/news/2698.html

相关文章:

  • Matlab自学笔记五十二:变量名称:检查变量名称是否存在或是否与关键字冲突
  • Nacos-3.0.0适配PostgreSQL数据库
  • 互容是什么意思?
  • python+selenium实现淘宝商品数据半自动查询
  • pg数据库删除模式
  • CVE-2024-3431 EyouCMS 反序列化漏洞研究分析
  • 道可云人工智能每日资讯|“人工智能科技体验展”在中国科学技术馆举行
  • 【原创】从s3桶将对象导入ES建立索引,以便快速查找文件
  • 基于 MeloTTS.cpp 的轻量级的纯 C++ 文本转语音(TTS)库
  • 相机-IMU联合标定:相机-IMU外参标定
  • 【二分查找】寻找峰值(medium)
  • 学生管理系统审计
  • 从零开始的二三维CAD软件开发: 系列经验分享-写在开头
  • TensorFlow深度学习实战——基于循环神经网络的文本生成模型
  • ExoPlayer 中的 Timeline、Period 和 Window
  • shell--数组、正则表达式RE
  • Flutter 学习之旅 之 flutter 作为 module ,在 Android 端主动唤起 Flutter 开发的界面 简单的整理
  • gitgitgit!
  • 关于CentOS7学习过程中遇到的一些问题
  • JAVA-StringBuilder使用方法
  • 文号验证-同时对两个输入框验证
  • Android开发,实现一个简约又好看的登录页
  • 谷歌浏览器js获取html宽度不准
  • 聊聊spring-boot-data-redis使用过程中的困惑(序列化,反序列化,Jackson, JavaType, TypeReference)
  • 第1篇:Egg.js框架入门与项目初始化
  • [leetcode]2302.统计得分小于k的子数组
  • HTML5 WebSocket:实现高效实时通讯
  • Win11安装Ubuntu20.04简记
  • 软件工程(二):开发模型
  • 传统农耕展陈如何突破?数字多媒体能否重构文化体验边界?