std::bind 的功能组合
Functional composition with std::bind
我正在阅读 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)
)?
叫做nested binding (i.e. std::bind
)。一个 std::bind
调用有一个或多个 std::bind
s.
在这种情况下,它的工作原理如下:
首先,调用嵌套的std::bind
表达式,意思是this
std::bind(std::plus<int>(), std::placeholders::_1, 10)
将第一个参数传递给 plus10times2
,并传递给外部参数:
即
std::bind(std::multiplies<int>(), /* result of nested bind */, 2);
由于嵌套绑定表达式(即内部 std::bind(std::plus<int>() ...
)returns 一个 int
eger,而外部绑定表达式(即 std::bind(std::multiplies<int>()...
)期望一个 int
ger 在那个地方,它完美地工作。
更多阅读: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
下面是 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 是 std::is_bind_expression::value == true 的类型 T(例如,另一个绑定表达式直接传递到对绑定的初始调用中),则绑定执行函数组合:而不是传递绑定子表达式 return 的函数对象,急切地调用子表达式,并将其 return 值传递给外部可调用对象。如果绑定子表达式有任何占位符参数,它们将与外部绑定共享(从 u1、u2 等中挑选出来)。具体来说,上面 std::invoke 调用中的参数 vn 是 arg(std::forward(uj)...) 并且同一调用中的类型 Vn 是 std::result_of_t&& (cv资格同g)."
所以,关键方面是我传递了一个参数 std::is_bind_expression<T>::value == true
,它修改了“正常”std::bind 行为
我正在阅读 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)
)?
叫做nested binding (i.e. std::bind
)。一个 std::bind
调用有一个或多个 std::bind
s.
在这种情况下,它的工作原理如下:
首先,调用嵌套的std::bind
表达式,意思是this
std::bind(std::plus<int>(), std::placeholders::_1, 10)
将第一个参数传递给 plus10times2
,并传递给外部参数:
即
std::bind(std::multiplies<int>(), /* result of nested bind */, 2);
由于嵌套绑定表达式(即内部 std::bind(std::plus<int>() ...
)returns 一个 int
eger,而外部绑定表达式(即 std::bind(std::multiplies<int>()...
)期望一个 int
ger 在那个地方,它完美地工作。
更多阅读: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
下面是 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 是 std::is_bind_expression::value == true 的类型 T(例如,另一个绑定表达式直接传递到对绑定的初始调用中),则绑定执行函数组合:而不是传递绑定子表达式 return 的函数对象,急切地调用子表达式,并将其 return 值传递给外部可调用对象。如果绑定子表达式有任何占位符参数,它们将与外部绑定共享(从 u1、u2 等中挑选出来)。具体来说,上面 std::invoke 调用中的参数 vn 是 arg(std::forward(uj)...) 并且同一调用中的类型 Vn 是 std::result_of_t
所以,关键方面是我传递了一个参数 std::is_bind_expression<T>::value == true
,它修改了“正常”std::bind 行为