Search code examples
c++c++11stdbind

Why can I store a callable target in a std::function which dosen't match the type


I have tried the following:

typedef std::function<void(int)> callback;

struct testclass
{
    void testfunc()
    {
        printf("test\n");
    }
};

int main()
{
    testclass test;
    callback c = std::bind(&testclass::testfunc, &test);
    c(1);
}

The output is

test

The std::bind returns a callable target like void(void), while the callback should be stored a void(int).

Why can I do this?


Solution

  • std::bind gives you back a function object that ignores any argument that doesn't have an associated placeholder. It's a loose match.

    For instance:

    auto f = []{}; // no arguments, do nothing
    f(1); // obviously ill-formed
    
    auto g = std::bind(f);
    g(); // okay, calls f()
    g(1); // okay, calls f()
    g(1, 2); // okay, calls f()
    

    In your example, you have a function<void(int)> that you're initializing with the result of a std::bind() call without placeholders. That works fine. The int argument of the function just gets ignored. It may or may not be what you actually want to do, but it's perfectly valid code.


    With a lambda, you could get the same effect by writing:

    callback c = [&test](int){ test.testfunc(); };
    

    Here we have to explicitly write the parameter though, whereas with bind it was implicitly ignored.