【问题标题】:std::bind a bound functionstd::bind 绑定函数
【发布时间】:2015-07-14 00:51:09
【问题描述】:

我在检测为什么这不编译时遇到了麻烦。我有一些 lambda 函数,它根据一些参数返回 std::function

我已将我的问题缩小到这个 sn-p(它不使用 lambda,但完美地重现了我的错误):

#include <functional>
#include <iostream>


struct foo {
    template<class T>
    void bar(T data) {
        std::cout << data << "\n";
    }
};

void some_fun(const std::function<void(int)> &f) {
    f(12);
}

int main() {
    foo x;
    auto f = std::bind(&foo::bar<int>, x, std::placeholders::_1);
    auto w = std::bind(some_fun, f);
    w();
}

w() 的调用产生了一个可爱的gcc 错误输出之一,我不知道出了什么问题。这是 gcc 4.6.1 回显的错误:

g++ -std=c++0x    test.cpp   -o test
test.cpp: In function ‘int main()’:
test.cpp:20:7: error: no match for call to ‘(std::_Bind<void (*(std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>))(const std::function<void(int)>&)>) ()’
/usr/include/c++/4.6/functional:1130:11: note: candidates are:
/usr/include/c++/4.6/functional:1201:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
/usr/include/c++/4.6/functional:1215:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
/usr/include/c++/4.6/functional:1229:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]
/usr/include/c++/4.6/functional:1243:2: note: template<class ... _Args, class _Result> _Result std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const volatile [with _Args = {_Args ...}, _Result = _Result, _Functor = void (*)(const std::function<void(int)>&), _Bound_args = {std::_Bind<std::_Mem_fn<void (foo::*)(int)>(foo, std::_Placeholder<1>)>}]

这里,f 应该是一些可调用对象,它接受一个 int 作为参数并使用它调用x.bar(int)。另一方面,w 只是一个调用some_fun(f) 的可调用对象,即f 上述可调用对象,具有some_fun 的参数所期望的签名。

我错过了什么吗?我可能不知道如何实际混合std::bindstd::function

【问题讨论】:

  • 当您将 auto 替换为 std::function&lt;void(int)&gt; for f 时,它似乎可以工作。
  • 这可能不是您问题的答案.. 但是您是否考虑过使用 C++11 附带的本机 lambda 函数(这使得 std::bind 变得不必要)?
  • 在 Boost 中,我们有 protect 来处理这种情况,但它似乎没有达到标准。
  • f 不是std::function,而是一些无法命名的绑定表达式类型。您必须将其显式转换为std::function。这是您不能使用auto 的情况之一。
  • this answer,特别是关于防止急切评估的部分(你不能不改变类型,因为std::is_bind_expression&lt;&gt;)。

标签: c++ function c++11 bind


【解决方案1】:

std::bind 表达式,就像它们的 boost::bind 前辈一样,支持一种组合操作。您对w 的表达大致相当于

auto w=std::bind(some_fun,  std::bind(&foo::bar<int>, x, std::placeholders::_1) );

以这种方式嵌套绑定被解释为

  1. 计算x.bar&lt;int&gt;(y) 的值,其中y 是传递给结果仿函数的第一个参数。
  2. 将结果传递给some_fun

但是x.bar&lt;int&gt;(y) 返回 void,而不是任何函数类型。这就是为什么它不能编译。

正如 K-ballo 指出的那样,使用 boost::bind,您可以使用 boost::protect 解决此问题。正如 Kerrek SB 和 ildjarn 指出的那样,解决此问题的一种方法是:不要将 auto 用于 f。您不希望 f 具有绑定表达式的类型。如果f 有其他类型,那么std::bind 将不会尝试应用函数组合规则。例如,你可以给f 类型std::function&lt;void(int)&gt;

std::function<void(int)> f = std::bind(&foo::bar<int>, x, std::placeholders::_1);
auto w = std::bind(some_fun, f);

由于f 并不真正具有绑定表达式的类型,std::is_bind_expression&lt;&gt;::value 将在 f 的类型上为 false,因此第二行中的 std::bind 表达式将只传递值逐字逐句,而不是尝试应用函数组合规则。

【讨论】:

    【解决方案2】:

    some_fun 想要const std::function&lt;void(int)&gt; &amp; 类型的参数。

    std::bind 返回“一个未指定类型 T 的函数对象”(查看提供的链接,“返回值”部分),您试图将其作为 some_fun 参数传递。

    这似乎会导致问题,因为这种参数类型不是预期的。

    看:http://en.cppreference.com/w/cpp/utility/functional/bind

    【讨论】:

    • 这根本不是根本问题——std::is_bind_expression&lt;&gt; 它的行为是。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多