std :: bind对我来说毫无意义

时间:2015-04-13 15:59:51

标签: c++ std-function

以下内容:

#include <functional>

struct Foo 
{
    void bar1() {}
    void bar2(int) {}
    void bar3(int, int) {}
    void bar4(int, int, int) {}
};


int main()
{
    Foo foo;

    auto f1 = std::bind(&Foo::bar1, &foo);
    auto f2 = std::bind(&Foo::bar2, &foo);
    auto f3 = std::bind(&Foo::bar3, &foo);
    auto f4 = std::bind(&Foo::bar4, &foo);

    f1(1, 2, 3, 4); // success
    f2(1, 2, 3);    // error
    f3(1, 2);       // error
    f4(1);          // error    

    return 0;
}

f1(1,2,3,4)编译并执行bar1()。 f2(1,2,3),没有编译,f3(1,2)没有编译(但是bar3有正确的原型)而f4(1)没有编译。我在Visual Studio 2013中遇到的这3个案例的错误是

&#34;类未定义&#39;运算符()&#39;或者用户定义的转换运算符到指向函数的指针或函数引用,它接受适当数量的参数&#34;

我对模板和标准库的理解有限,但这对我来说似乎没有任何合理意义。是否有合理的简单解释?

2 个答案:

答案 0 :(得分:14)

要将参数传递给目标,您需要在绑定表达式中提供这些参数,或者通过向绑定表达式添加占位符使其保持未绑定状态,然后必须使用参数调用该函数来替换占位符。

您可以在没有占位符的情况下致电bar1,因为它没有任何参数,因此您不需要传递任何内容。传递给f1的参数只是被忽略,因为没有未绑定的参数,即没有需要替换的占位符。

其他函数需要参数,因此您必须在&#34;绑定时间&#34; e.g。

auto f2a = std::bind(&Foo::bar2, &foo, 1);
f2a();

或保持参数未绑定,并在调用可调用对象时提供它们:

auto f2b = std::bind(&Foo::bar2, &foo, std::placeholders::_1);
f2b(1);

请注意,GCC 5现在具有静态断言来捕获此类错误。如果可以确定目标函数的arity并且绑定表达式没有为目标函数的每个参数设置绑定参数或占位符,那么它会说:

/ usr / local / gcc-head / include / c ++ / 5.0.0 / functional:1426:7:错误:静态断言失败:指向成员的参数数量错误

您所写的内容与此相同,使用lambdas而不是bind

Foo foo;

auto f1 = [&foo](...) { return foo.bar1(); };
auto f2 = [&foo](...) { return foo.bar2(); };
auto f3 = [&foo](...) { return foo.bar3(); };
auto f4 = [&foo](...) { return foo.bar4(); };

f1(1, 2, 3, 4); // success
f2(1, 2, 3);    // error
f3(1, 2);       // error
f4(1);          // error   

即。你定义将接受任何参数的仿函数,但忽略它们,然后调用Foo的成员函数,但不一定使用正确的参数。

答案 1 :(得分:4)

您似乎对bind应该做的事情有误解 您传递给bind结果的参数将被“替换”到占位符_1_2,依此类推。与占位符不对应的参数未被使用,因此被忽略。由于您未在绑定表达式中使用任何占位符,因此对bar1的内部调用始终等效于foo.bar1() - 因此它与您传递给bind结果的参数无关。

现在很明显,对bar4的调用等同于foo.bar4(),但bar4需要四个参数,所以这是无意义的。您可以通过编写

来解决这个问题
using namespace std::placeholders;
auto f4 = std::bind(&Foo::bar4, &foo, _1, _2, _3, _4);

现在,如果您提供四个参数,那么这些参数将被正确传递,并且内部调用将等同于例如foo.bar4(1, 2, 3, 4)