当 bind
将 bind
创建的函数对象作为函数的参数时,我遇到了问题。
我有两个函数 fa
和 fb
。 fa
接受一个函数作为参数。我将 fa
和函数(在这种情况下为 fb
)绑定(bind)到一个闭包中。我用两种不同的方式来做,如下所示。第一个有效,第二个不编译。
(我知道,我不需要在标记的行上绑定(bind),因为没有参数。当然,这只是展示行为的最小示例,实际上我会将参数绑定(bind)到 fb
)
void fa(function<void()> f){
f();
}
void fb(){
}
void test_which_compiles() {
auto bb = fb; // *** QUESTIONABLE LINE ***
auto aa = std::bind(fa, bb);
aa();
}
void test_which_fails() {
auto bb = std::bind(fb); // *** QUESTIONABLE LINE ***
auto aa = std::bind(fa, bb);
aa(); // COMPILE ERROR HERE
}
调用aa()
时出现编译错误。
因此,当我将函数对象绑定(bind)为参数时,编译器似乎不接受它本身是由 bind 创建的。
编译错误是一长串我不认为与该行直接相关的东西。我只给出第一行:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/type_traits:3476:13:
error: no matching function for call to '__invoke'
__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...)
编译器是启用了 C++11 的 Apple LLVM 版本 6.1.0 (clang-602.0.53)(基于 LLVM 3.6.0svn)
。
std::bind
返回一些未指定的仿函数,当嵌套在另一个仿函数中时具有神奇的行为 bind
表达。您可以通过包装该返回类型来禁用这种神奇的行为,例如。通过声明bb
作为:
std::function<void()> bb = std::bind(fb);
如果 bb 真的有参数,这同样有效:
std::function<void()> bb = std::bind(fb, 42);
有关解释,请参阅成员函数运算符() 下的第二个项目符号here :
If std::is_bind_expression<T>::value == true
(i.e. another bind subexpression was used as an argument in the initial call to bind), then that bind subexpression is invoked immediately and its result is passed to the invocable object. If the bind subexpression has any placeholder arguments, they are picked from u1, u2, ....
这个例子展示了嵌套的绑定(bind)表达式行为和(我认为)你真正想要的行为。 编辑 - 现在还包括来自评论的 Yakk 的转发包装器:比使用 function
更多的输入或 lambda,但更轻量级。
#include <iostream>
#include <functional>
void f(int n1, int n2, int n3) {
std::cout << n1 << ' ' << n2 << ' ' << n3 << '\n'; }
void g(int n1, std::function<int()> fun, int n3) {
std::cout << n1 << ' ' << fun() << ' ' << n3 << '\n'; }
int h(int n) { return n; }
namespace Yakk {
template <class F> struct f_t {
F f;
template <class...Ts>
std::result_of_t<F const&(Ts...)> operator()(Ts&&...ts) const& {
return f(std::forward<Ts>(ts)...);
} /* similar for &, &&, const&& */
};
template <class F> f_t<std::decay_t<F>> f(F&& fin) {
return {std::forward<F>(fin)};
}
}
int main() {
using namespace std::placeholders;
auto subexpr = std::bind(h, _2);
auto magic = std::bind(f, _1, subexpr, 42);
magic(7, 11);
std::function<int()> nested = std::bind(h, 11);
auto nomagic = std::bind(g, _1, nested, 42);
nomagic(7);
auto yakkmagic = std::bind(g, _1, Yakk::f(std::bind(h, 11)), 42);
yakkmagic(7);
}