【问题标题】:Functional composition with std::bind使用 std::bind 的功能组合
【发布时间】:2020-08-28 05:07:02
【问题描述】:

我正在阅读Nicolai Josuttis关于 C++11 STL 的精美书籍的第二版。

我找到了以下代码:

#include <functional>
#include <iostream>

int main()
{
   auto plus10 = std::bind(std::plus<int>(),
      std::placeholders::_1,
      10);
   std::cout << "+10:    " << plus10(7) << std::endl;

   auto plus10times2 = std::bind(std::multiplies<int>(),
      std::bind(std::plus<int>(),
         std::placeholders::_1,
         10),
      2);
   // ...
}

我无法理解绑定对象“plus10times2”的工作原理。 它不应该绑定到 int 参数吗?

它如何绑定另一个绑定对象?调用plus10times2 的调用操作符时如何工作(例如plus10times2(7))?

【问题讨论】:

    标签: c++ function c++11 stdbind callable-object


    【解决方案1】:

    它被称为nested binding (i.e. std::bind)。一个std::bind 调用有一个或多个std::binds。

    在这种情况下,它的工作原理如下:

    首先,调用嵌套的std::bind 表达式,意思是这个

    std::bind(std::plus<int>(), std::placeholders::_1, 10) 
    

    将第一个参数传递给plus10times2,并传递给外部参数: 即

    std::bind(std::multiplies<int>(), /* result of nested bind */, 2);
    

    由于嵌套的绑定表达式(即内部的std::bind(std::plus&lt;int&gt;() ...)返回一个integer,而外部的绑定表达式(即std::bind(std::multiplies&lt;int&gt;()...)在那个地方期望一个intger,它工作得很好。

    更多阅读:Nested bind expressions


    话虽如此,从 C++11 开始,我们还有 lambda function。在 lambda 调用中将嵌套的绑定表达式写入 equalent 可能会清除问题:

    const auto plus10_lmda = [](int arg) { return std::plus{}(arg, 10); };
    const auto plus10times2_lmda = [](auto callblePlus, int innerArg) { return std::multiplies{}(callblePlus(innerArg), 2); };
    std::cout << plus10times2_lmda(plus10_lmda, 7);   // prints 34
    

    或完全嵌套并立即调用内部 lambda

    const auto plus10times2_lmda = [](int innerArg) { 
       return std::multiplies{}(
          [](int arg) { return std::plus{}(arg, 10); }(innerArg) // invoke the inner one immediately
          , 2); 
    };
    std::cout << plus10times2_lmda(7);  // prints 34
    

    【讨论】:

    • 对于嵌套绑定表达式 std::bind(std::plus(), std::placeholders::_1, 10) ,它是返回整数的 CALL 运算符,但是谁叫它? std;;bind 不只是从参数中复制构造其绑定参数吗?
    【解决方案2】:

    下面是来自 cppreference.com 的关于 std::bind 的摘录:

    “给定一个从较早的 bind 调用中获得的对象 g,当它在函数调用表达式 g(u1, u2, ... uM) 中调用时,会发生对存储对象的调用,就像通过 std ::invoke(fd, std::forward(v1), std::forward(v2), ..., std::forward(vN)),其中 fd 是 std::decay_t 类型的值 值和类型绑定参数 v1、v2、...、vN 的确定如下所示。

    ...

    如果存储的参数 arg 是类型 T 且 std::is_bind_expression::value == true (例如,另一个绑定表达式直接传递到对 bind 的初始调用中),则 bind 执行函数组合:而不是传递绑定子表达式将返回的函数对象,立即调用子表达式,并将其返回值传递给外部可调用对象。如果绑定子表达式有任何占位符参数,它们将与外部绑定共享(从 u1、u2、...中挑选出来)。具体来说,上述 std::invoke 调用中的参数 vn 是 arg(std::forward(uj)...) ,同一调用中的类型 Vn 是 std::result_of_t&&(cv限定和g一样)。”

    因此,关键方面是我传递了一个参数 std::is_bind_expression&lt;T&gt;::value == true,并修改了“正常”的 std::bind 行为

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-27
      • 2018-10-29
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      相关资源
      最近更新 更多