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

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相比,它具有自己独特的优势和适用场景。在实际开发中,我们可以根据具体的需求选择合适的绑定工具。

相关文章:

  • Scratch——第20课 辗转相除法/绳子算法
  • FTP-网络文件服务器
  • Docker 容器虚拟化技术和自动化部署
  • Java面试:Spring及Spring Cloud技术深度剖析
  • 基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
  • Nacos源码—1.Nacos服务注册发现分析二
  • 驱动开发硬核特训 │ 深度解析 fixed regulator 驱动与 regulator_ops
  • Linux 命令行利用 speedtest 测速
  • MySQL 的覆盖索引是什么?
  • 8.Android(通过Manifest配置文件传递数据(meta-data))
  • 【lammps】后处理 log.lammps
  • 如何在idea 中写spark程序
  • Linux学习笔记(一):Linux下的基本指令
  • 详解RabbitMQ工作模式之简单模式
  • 天猫TP代运营服务商-品融电商:助力品牌破局增长的专业推手
  • 智慧健康养老实训室建设方案:科技引领养老健康服务人才培养
  • 技术与文化双轮驱动:数字化转型的核心要素
  • 运维实施27-Linux权限管理
  • OpenGL进阶系列21 - OpenGL SuperBible - blendmatrix 例子学习
  • Pytorch深度学习框架60天进阶学习计划 - 第53天:自监督学习范式(一)
  • 西班牙遭遇史上最严重停电,已进入国家紧急状态
  • 马上评丨机械停车库成“僵尸库”,设计不能闭门造车
  • 气温“过山车”现象未来或更频繁且更剧烈
  • 滨江集团去年营收约691亿元,尚未结算的预收房款1253亿元
  • 5145篇报道中的上海车展:40年,什么变了?
  • 2025年“畅游江淮 合肥等侬”文旅推介会在沪成功举办