为什么以下编译即将自由函数作为带有正确签名的参数传递:
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);
而另一个不编译,即传递具有相同签名的boost::bind
类成员函数的结果:
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);
错误消息如下:
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);
更新:重载的set_min_objective
是:
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);
答案 0 :(得分:3)
你需要定义set_min_objective,它接受boost :: function作为第一个参数:
typedef boost::function<double (unsigned n, const double *x, double *grad, void *f_data)> func_t;
...
void set_min_objective(func_t, void*);
...
另一件事 - 你最好不要使用NULL
答案 1 :(得分:2)
这是一个简单的示例,它演示了您的问题:
#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;
}
主要原因是boost::function<>
不是可转换到函数指针,所以你需要提供一个接受它的重载(如上所述。)
编辑:只是为了进一步澄清事情。 boost::bind()
不显式返回boost::function<>
,但是,它返回的对象可以存储在boost::function<>
的正确实例中,在上述情况下,正确实例化是boost::function<int(int, int, int)>
。
通常情况下,如果您有兴趣传播它(没有模板)或存储它以供以后使用,您只需要将其存储在boost::function
中。在这种情况下,当您传递bind()
的结果时,您需要使用正确的重载来接受来自boost::bind()
的返回对象,并且最简单的方法是在不使用模板的情况下执行此操作接受boost::function
(如上所述。)
通常情况下,我是务实的,所以我会在可能的情况下诉诸于此(不知道你想对f
做什么)。
template <typename F>
double set_min_objective(F f, ...)
{
}
然后你是不可知论者,当然纯粹主义者会有其他意见。
注意:boost::function<>
的一个好处是你可以将一个非成员函数指针存储在一个中(只要签名匹配。)所以实际上你只需要一个接受你的函数的版本正确的boost::function<>
,它将适用于两种情况(成员函数boost::bind()
和非成员函数。)
EDIT2:好的,鉴于附加信息,您必须使用以下机制,您需要拥有类的非成员函数,然后将其委托给成员函数,例如:
<>
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
}
};
这是第三方库采用的典型模式,与用户代码无关。
答案 2 :(得分:0)
set_min_objective
的两个重载都期望指向函数的指针作为第一个参数,但boost::bind
返回的对象不是指向函数的指针,它是一个函数对象。
boost::bind
返回一个存储目标函数和任何绑定参数的函数对象,它不合成函数并返回指向它的指针,或者将指向成员函数的指针神奇地转换为指针-to-功能。那将是神奇的。