确保std :: bind提供正确数量的参数

时间:2018-07-25 07:41:37

标签: c++

更改std::function的签名后,我想知道编译器是否会抱怨我尚未更改的函数签名。

基本上,我的代码如下:

#include <functional>
#include <iostream>
#include <vector>

class CallbackCaller
{
public:
    typedef std::function<void (unsigned, int)> CallbackFunction;

    void registerCallbackFunction(CallbackFunction cb_function)
    {
        callback_functions_.push_back(cb_function);
    }

    void callThemAll()
    {
        for (CallbackFunction &cb_function : callback_functions_)
            cb_function(5, -3);
    }

private:
    std::vector<CallbackFunction> callback_functions_;
};

class CallbackHandler
{
public:
    CallbackHandler(CallbackCaller &callback_caller)
    {
        callback_caller.registerCallbackFunction(std::bind(&CallbackHandler::f1, this, std::placeholders::_1)); // !!!
        callback_caller.registerCallbackFunction(std::bind(&CallbackHandler::f2, this, std::placeholders::_1, std::placeholders::_2));
    }

private:
    void f1(unsigned x)
    {
        std::cout << "f1: " << x << std::endl;
    }

    void f2(unsigned x, int y)
    {
        std::cout << "f2: " << x << ", " << y << std::endl;
    }
};

int main()
{
    CallbackCaller callback_caller;
    CallbackHandler callback_handler(callback_caller);
    callback_caller.callThemAll();
    return 0;
}

为什么registerCallbackFunction接受f1,即使其签名不匹配?有没有办法使此代码的编译失败?

1 个答案:

答案 0 :(得分:4)

std::bind对将其存储在期望特定事物的std::function中这一事实没有任何预见。它只知道给定的成员函数的签名。因此,这将要求您绑定this一个占位符

此后,它仅向函数对象提供模板化可变参数函数调用运算符。所述函数调用运算符具有接受任意数量的参数的属性,并且不使用任何多余的参数。它不会抱怨,它只会进行评估,然后继续忽略不需要的内容。再说一次,它只需要一个参数。

std::function依次检查是否可以使用2个参数调用给出的函子。模板化函数调用运算符可以做到这一点。它接受第二个参数,并将其丢弃。完全合法。

std::bind的更好替代品是通用lambda:

//callback_caller.registerCallbackFunction([this](auto&& ...x) {f1(std::forward<decltype(x)>(x)...);}); // !!!
callback_caller.registerCallbackFunction([this](auto&& ...x) {f2(std::forward<decltype(x)>(x)...);});

现在进行类型擦除的次数要少得多,并且赋予lambda的参数数量必须与预期的参数f1f2匹配,否则会出错。

从C ++ 14开始,std::bind的用例实际上不存在。