4

我正在阅读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 参数吗?

它如何绑定另一个绑定对象?调用调用运算符时它是如何工作的plus10times2plus10times2(7)例如)?

4

2 回答 2

3

它被称为嵌套绑定(即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);

由于嵌套的绑定表达式(即 inner std::bind(std::plus<int>() ...)返回一个integer,而外部的 bind 表达式(ie std::bind(std::multiplies<int>()...)在那个地方期望一个intger,所以它工作得很好。

更多阅读:嵌套绑定表达式


话虽如此,从 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
于 2020-08-28T05:43:36.110 回答
0

下面是 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<T cv &(Uj&&...) >&& (cv 限定与 g 相同)。"

所以,关键方面是我传递了一个参数,它std::is_bind_expression<T>::value == true修改了“正常”的 std::bind 行为

于 2020-08-28T06:14:41.050 回答