Question

I'm trying to make a boost::bind call and save value of passed argument in boost::function and I stumbled upon case I can't explain:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <memory>
#include <iostream>

template <class T>
using callback = boost::function<void (int, std::shared_ptr<T>)>;

class work
{
public:
    int value;
};


void job_callback(int v, std::shared_ptr<int> work)
{
    *work = v;
}

int main()
{
    std::shared_ptr<int> a(new int(10));
    boost::bind(job_callback, _1, a)(1); // compiles and works with 1 arg, *a is 1
    callback<int> call = boost::bind(job_callback, _1, a); // compiles
    call(2, a); // compiles and works with 2 args, *a is 2

    call(3); // does not compile with 1 arg

    return 0;
}

I can't understand why boost::bind(job_callback, _1, a)(1) works, even though only one argument is provided to the resulting functor - so the second argument is passed through - but call(3) doesn't compile with the following error:

/usr/include/boost/function/function_template.hpp:761:17: note: boost::function2<R, T1, T2>::result_type boost::function2<R, T1, T2>::operator()(T0, T1) const [with R = void; T0 = int; T1 = std::shared_ptr<int>; boost::function2<R, T1, T2>::result_type = void]
/usr/include/boost/function/function_template.hpp:761:17: note:   candidate expects 2 arguments, 1 provided

Is the return type from that boost::bind call not boost::function<void (int, shared_ptr<int>)> but something else, something that stores the value of the second argument? If so, what is it?

Was it helpful?

Solution

Since the boost and std {bind,function} produce the same problem. I will use std version for discussion. I think the problem is with the assignment to function object.

callback<int> call = boost::bind(job_callback, _1, a); // compiles

It compiles but is incorrect because callback<int> == function<void (int,xxx)>. This is not the right signature because one of the two parameters has been fixed to a.

But what's really confusing here is probably why the function object should accept the bind result when it is not the of the right arity? I think that's maybe related to the flexibility introduced in std::bind to handle extra parameters. I suspect this happens in boost as well. But I am not 100% sure on this. I never understand why bind should tolerate incorrect number of parameters.

The correct usage is to

function<void (int)> call = std::bind(job_callback, _1, a); //also compiles

Code using std::{function,bind}

#include <functional>
#include <memory>
#include <iostream>
using namespace std;
using namespace std::placeholders;

template <class T>
using callback = std::function<void (int, std::shared_ptr<T>)>;

class work
{
public:
    int value;
};


void job_callback(int v, std::shared_ptr<int> work)
{
    *work = v;
}

int main()
{
    std::shared_ptr<int> a(new int(10));
    std::bind(job_callback, _1, a)(1); // compiles and works with 1 arg, *a is 1
    //callback<int> call = std::bind(job_callback, _1, a); // compiles
    function<void (int)> call = std::bind(job_callback, _1, a); //also compiles
    //call(2, a); // compiles and works with 2 args, *a is 2

    call(3); // does not compile with 1 arg

    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top