Why does the following compiles i.e. passing a free function as parameter with the right signature:
inline double free_adapter_f(unsigned n, const double *x, double *grad, void *d) {
return 0.0;
}
nlopt::opt opt(nlopt::LN_NELDERMEAD, X.size());
opt.set_min_objective(free_adapter_f, NULL);
whereas this other doesn't compile i.e. passing the result of boost::bind
a class member function with the same signature:
template<class Space, class Solution, class Oracle>
inline double NelderMead<Space, Solution, Oracle>::adapter_f(unsigned n, const double *x, double *grad, void *d) {
return 0.0;
}
nlopt::opt opt(nlopt::LN_NELDERMEAD, X.size());
opt.set_min_objective(boost::bind(&NelderMead::adapter_f, this, ::_1, ::_2, ::_3, ::_4), NULL);
The error message is the following:
nelder_mead.h(98): error: no instance of overloaded function "nlopt::opt::set_min_objective" matches the argument list
argument types are: (boost::_bi::bind_t<double, boost::_mfi::mf4<double, NelderMead<TestSpace, VectorXd, oracle_f>, unsigned int, const double *, double *, void *>, boost::_bi::list5<boost::_bi::value<NelderMead<TestSpace, VectorXd, oracle_f> *>, boost::arg<1>, boost::arg<2>, boost::arg<3>, boost::arg<4>>>, long)
object type is: nlopt::opt
opt.set_min_objective(boost::bind(&NelderMead::adapter_f, this, ::_1, ::_2, ::_3, ::_4), NULL);
UPDATE: the overloaded set_min_objective
are:
typedef double (*func)(unsigned n, const double *x, double *grad, void *f_data);
typedef double (*vfunc)(const std::vector<double> &x, std::vector<double> &grad, void *f_data);
void set_min_objective(func f, void *f_data);
void set_min_objective(vfunc vf, void *f_data);
Here is a simple example, which demonstrates your problem:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
namespace g
{
typedef int (*func)(int a, int b, int c);
void bar(func f)
{
std::cout << "g::bar:: called" << (*f)(10, 20, 30) << std::endl;
}
// Disable the over load below and you will get the same error
void bar(boost::function<int(int, int, int)> f)
{
std::cout << "g::bar:: called" << f(10, 20, 30) << std::endl;
}
}
template <typename A, typename B, typename C>
class foo
{
public:
int bar(int a, int b, int c) const
{ return a + b + c; }
void call()
{
g::bar(boost::bind(&foo::bar, this, ::_1, ::_2, ::_3));
}
};
int main(void)
{
foo<int, double, int> f;
f.call();
return 0;
}
Main reason is that boost::function<>
is not convertible to a function pointer, so you need to provide an overload which accepts this (as above.)
EDIT: just to clarify things a little further. boost::bind()
does not explicitly return a boost::function<>
, however, the object it returns can be stored in the correct instantiation of boost::function<>
, in the above case, the correct instantiation is boost::function<int(int, int, int)>
.
Normally you would only need to resort to storing it in a boost::function
if you were interested in propagating it (without a template) or storing it for later use. In this case, as you are passing the result of the bind()
, you need to have the correct overload to accept the returned object from boost::bind()
, and the easiest way to do this without resorting to templates is to accept a boost::function
(as above.)
Normally, I'm pragmatic, so I would resort to this (without knowing what you are wanting to do with f
) where possible.
template <typename F>
double set_min_objective(F f, ...)
{
}
Then you are agnostic, of course purists will have other opinions.
NOTE: A nice thing with boost::function<>
is that you can store a non-member function pointer in one too (as long as the signature matches.) So in reality you only need a version of your function which accepts the correct boost::function<>
and it will work in both cases (member function with boost::bind()
and non-member function.)
EDIT2: Okay, given the additional information, you have to resort to the following mechanism, you need to have a non-member function of your class, which will then delegate to the member function, for example:
<>
class NelderMead
{
static double delegate_f(unsigned n, const double *x, double *grad, void *f_data)
{
// I'm assuming here the frame work passed you whatever you gave in f_data
NelderMead* inst = reinterpret_cast<NelderMead*>(f_data);
return inst->adapter_f(n, x, grad);
}
double adapter_f(unsigned n, const double *x, double *grad)
{
}
void set()
{
nlopt::opt opt(nlopt::LN_NELDERMEAD, X.size());
opt.set_min_objective(delegate_f, this); //<-- here pass the instance as the additional data
}
};
This is a typical pattern employed by third-party libraries which are meant to be agnostic to user code.