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?
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;
}