• C++新特性 | bind & function


    std::bind

    概述

    std::bind 是一个C++函数模板,简单说它就像一个函数适配器,用来接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。 该函数模板定义在头文件 #include 中。

    C++中的可调用对象:函数、函数指针、lambda表达式、bind对象、函数对象。lambda表达式和bind对象是C++新标准中提出的,其他可调用对象在旧标准中就已存在。

    bind 可以把一个原本接收 N 个参数的函数 origFunc(...),通过绑定(个人觉得此处的绑定让人难以理解 bind 的作用,感觉用固定或者给定更好理解)一些参数,返回一个接收 M 个(一般情况M小于N,当大于等于N时似乎多的参数没有实际意义)参数的新函数 newFunc(...)。同时,使用 std::bind 还可以实现参数顺序的调整等操作。

    函数原型

    1. // FUNCTION TEMPLATE bind (implicit return type)
    2. template <class _Fx, class... _Types>
    3. _NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
    4. return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
    5. }
    6. // FUNCTION TEMPLATE bind (explicit return type)
    7. template <class _Ret, class _Fx, class... _Types>
    8. _NODISCARD _CONSTEXPR20 _Binder<_Ret, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
    9. return _Binder<_Ret, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
    10. }

    上述函数原型为 VS2019 中的具体模板,可以看到 std::bind 有两种函数原型。

    作用:用来返回基于 _Fx 的函数对象,参数被绑定到可变参数 _Args 中。每个参数都可以绑定到一个值或者一个占位符(bind 返回的 newFunc(..,) 的参数)。

    bind 注意事项

    • bind 预先绑定的参数需要传递具体的变量或者值进去,对于预先绑定的参数,是通过值传递的。如果该参数被 std::ref 或者 std::cref 包装,则是通说引用传递。
    • bind 未预先绑定的参数,需要使用 std::placeholders(占位符),占位符从 _1 (表示原始可调用对象的第1个参数)开始递增。需要注意的是 std::placeholders 是按照引用传递的。
    • bind 绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址,这是因为对象的成员函数需要有 this 指针。并且编译器不会将对象的成员函数隐式转换成函数指针,需要通过 & 手动转换。
    • bind 返回值是可调用的实体,可以直接赋值给 std::function() 对象。
    • 对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的;类的this可以通过对象或者指针来绑定。

    测试实例

    1. #include
    2. void addTwoNum(int a, int b) {
    3. cout << "a+b= " << a + b << endl;
    4. }
    5. struct INFOS {
    6. int year;
    7. int month;
    8. int day;
    9. void mergeDay() {
    10. string ret_str;
    11. ret_str = to_string(year) + "-" + to_string(month) + "-" + to_string(day);
    12. cout << "merged date info: " << ret_str << endl;
    13. }
    14. };
    15. int main() {
    16. // bind 绑定函数
    17. auto calSum = bind(addTwoNum, 1, std::placeholders::_1);
    18. calSum(10);
    19. auto calSum1 = bind(addTwoNum, 2, 3);
    20. calSum1();
    21. // bind 绑定函数成员对象
    22. INFOS information = {2022, 2, 23};
    23. auto dayInfos = bind(&INFOS::day, &information);
    24. cout << "day infos: " << dayInfos() << endl;
    25. auto mergeDate = bind(&INFOS::mergeDay, &information);
    26. mergeDate();
    27. INFOS infos = {2018, 8, 7};
    28. auto mergeDateUsNewParms = bind(&INFOS::mergeDay, std::placeholders::_1);
    29. mergeDateUsNewParms(infos);
    30. return 0;
    31. }
    32. /// Terminal output results:
    33. a+b= 11
    34. a+b= 5
    35. day infos: 23
    36. merged date info: 2022-2-23
    37. merged date info: 2018-8-7

    std::function

    概述

    由于可调用对象的定义方式较多,但是函数的调用方式较为类似,因此需要使用一个统一的方式保存可调用对象或者传递可调用对象。std::function 就可以实现该需求。

    std::function 是一个通用的、多态的可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象(普通函数、Lambda表达式、函数指针、以及其它函数对象等),它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。可以对可以调用的目标实体进行存储、复制、和调用操作。

    通过 std::function 可以形成一个新的可调用的std::function对象;让我们不再纠结那么多的可调用实体。

    std::function 对象是对C++中现有的可调用实体的一种类型安全的包装(因为函数指针这类可调用实体,是类型不安全的)。

    测试实例

    1. int add(int a, int b) {
    2. return a + b;
    3. }
    4. auto multiply = [](int a, int b) {
    5. return a * b;
    6. };
    7. struct divs {
    8. int operator() (int a, int b) {
    9. return a / b;
    10. }
    11. };
    12. int main() {
    13. function<int(int, int)> addTwoNum = add;
    14. function<int(int, int)> multiTwoNum = multiply;
    15. function<int(int, int)> divTwoNum = divs();
    16. cout << addTwoNum(12, 23) << endl;
    17. cout << multiTwoNum(2, 4) << endl;
    18. cout << divTwoNum(12, 4) << endl;
    19. return 0;
    20. }
    21. /// Terminal output results:
    22. 35
    23. 8
    24. 3
  • 相关阅读:
    AMR论文阅读之:ATP: AMRize Then Parse! Enhancing AMR Parsing with PseudoAMRs
    SpringBoot中有几种定义Bean的方式?
    数仓总结题
    Git学习1
    手机连接电脑后资源管理器无法识别(识别设备但无法访问文件)
    VS2022升级之后,原有项目出现异常
    灵性图书馆:好书推荐-《断轮回》
    C语言——二周目——程序的翻译与执行环境
    C++ Qt 开发:ListWidget列表框组件
    集成电路运算放大器[23-9-16]
  • 原文地址:https://blog.csdn.net/qq_38844835/article/details/127639714