-1

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);
SkyWalker
  • 13,729
  • 18
  • 91
  • 187

3 Answers3

3

You need to define set_min_objective which accepts boost::function as first parameter:

 typedef boost::function<double (unsigned n, const double *x, double *grad, void *f_data)> func_t;
 ...
 void set_min_objective(func_t, void*);
 ...

another thing - you'd better not to use NULL

AlexT
  • 1,413
  • 11
  • 11
  • Aha, okay, you've said the same thing, +1, I'll leave my answer as up as it has the SSCCE which demonstrates this. – Nim Feb 25 '14 at 14:52
  • I can't do that because `set_min_objective` belongs to a third party library that I prefer not to modify. In fact this code is an attempt to adapt the signature of my optimizer framework to this third party library NLOpt. – SkyWalker Feb 25 '14 at 15:04
  • @GiovanniAzua in this case the only thing that you can do is to define function which adapts your NelderMead::adapter_f. This is ugly but works: `NelderMead instance; double nelder_mead_adapter_f(unsigned n, const double *x, double *grad, void *d) { return instance.adapter_f(n, x, grad, d); }` so you can pass this free function to NLOpt interface. – AlexT Feb 25 '14 at 15:22
  • Exactly I can't live with static singleton instances for this. I need to be able to handle it at instance level. – SkyWalker Feb 25 '14 at 15:33
2

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.

Nim
  • 33,299
  • 2
  • 62
  • 101
  • `boost::bind` does not return a `boost::function` so it's not immediately obvious what `boost::function` has to do with anything. If you explained that the right specialization of `boost::function` can store the object returned by `boost::bind` (among other things) that might help. – Jonathan Wakely Feb 25 '14 at 14:52
  • @JonathanWakely, yip, editing... – Nim Feb 25 '14 at 14:55
  • +1, thanks for explaining what is SSCCE – AlexT Feb 25 '14 at 14:58
  • `set_min_objective` belongs to a third party library NLopt which I'd prefer not to modify. In fact, I am trying to adapt two different optimization oracle function interfaces so I can use my framework and be able to plugin this external library. – SkyWalker Feb 25 '14 at 15:11
0

Both overloads of set_min_objective expect a pointer-to-function as the first parameter, but the object returned by boost::bind is not a pointer-to-function, it's a function object.

boost::bind returns a function object that stores the target function and any bound arguments, it doesn't synthesize a function and return a pointer to it, or magically turn a pointer-to-member-function into a pointer-to-function. That would be magic.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521