c++ - 全局函数和非静态成员函数指针设计

标签 c++ templates

我有一个持续优化算法,它采用 Oracle 函数作为模板参数。具体优化等级定义为:

template<class Space, class Solution, class Oracle>
class ConjugateGradient : public ContinuousOptimizerInterface<Space, Solution, Oracle> {
public:

    // Returns the optimal solution found for a given search space
    virtual const Solution& search(const Space& space, Oracle f);
};

作为搜索实现的一部分,我调用了 oracle 函数:

template<class Space, class Solution, class Oracle> 
inline const Solution& ConjugateGradient<Space, Solution, Oracle>::search(const Space& space, Oracle f) {
     // ...
     // get function value and gradient at X
     double fx;
     Solution dfx;
     tie(fx, dfx) = f(X);
     // ..
}

使用全局二次函数的简单示例:

typedef tuple<double, VectorXd> (*oracle_f)(const VectorXd&);
static tuple<double, VectorXd> f(const VectorXd& X) {
     double f = pow((4.0-X(0)), 2) + 10.0;
     VectorXd df = 2.0*X - VectorXd::Ones(X.rows())*8.0;
     return make_tuple(f, df);
}

// ...
ConjugateGradient<TestSpace, VectorXd, oracle_f> optimizer;
VectorXd optimal = optimizer.search(TestSpace(), f);

这工作正常,但现在我需要能够将类的非静态成员函数作为 Oracle 函数传递给 ConjugateGradient 算法。我需要如何将 Oracle 函数的 ConjugateGradient 模板声明和实现更改为全局函数或非静态成员函数?另一种方法是创建一个全局包装函数并使用可变参数将参数传递给包装函数,但这很丑陋而且不是类型安全的。

更新:此示例使用下面答案的绑定(bind)思想,但使用 boost::bind 而不是 std::bind,因为我不使用 C++11 和 std::bind仅适用于 C++11。

#include <Eigen/Dense>
#include <boost/tuple/tuple.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

using namespace Eigen;
using namespace boost;

// the class is parameterized with the appropriate minimizer strategy
enum Minimizer { kNormalEquations, kConjugateGradient };

template <Minimizer M = kNormalEquations>
class SomeANN : AnnInterface {
private:
    // ...
public:
    // define the oracle function type and member function
    typedef tuple<double, VectorXd> (SomeANN::*oracle_f)(const VectorXd&);
    tuple<double, VectorXd> f(const VectorXd& theta);
};

template <>
inline tuple<double, VectorXd> SomeANN<kConjugateGradient>::f(const VectorXd& theta) {
    double f = 0.0;
    VectorXd df;
    return make_tuple(f, df);
}

// ridge solver using conjugate gradient
template <>
inline void SomeANN<kConjugateGradient>::ridge_solve(const VectorXd& Y) {
    ConjugateGradient<BeginSpace, VectorXd, SomeANN::oracle_f> optimizer;
    // ...
    optimizer.search(BeginSpace(Y.rows()), boost::bind(&SomeANN::f, this, _1));
}

然后我收到错误:

some_ann.h:163:84: error: no matching function for call to 'ConjugateGradient<BeginSpace, Eigen::Matrix<double, -0x00000000000000001, 1>, boost::tuples::tuple<double, Eigen::Matrix<double, -0x00000000000000001, 1> > (SomeANN<(Minimizer)1u>::*)(const Eigen::Matrix<double, -0x00000000000000001, 1>&)>::search(BeginSpace, boost::_bi::bind_t<boost::tuples::tuple<double,  Eigen::Matrix<double, -0x00000000000000001, 1> >, boost::_mfi::mf1<boost::tuples::tuple<double, Eigen::Matrix<double, -0x00000000000000001, 1> >, SomeANN<(Minimizer)1u>, const Eigen::Matrix<double, -0x00000000000000001, 1>&>,  boost::_bi::list2<boost::_bi::value<SomeANN<(Minimizer)1u>*>, boost::arg<1> > >)'
conjugate_gradient.h:67:2: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
conjugate_gradient.h:84:3: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
conjugate_gradient.h:111:5: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
conjugate_gradient.h:153:4: error: must use '.*' or '->*' to call pointer-to-member function in 'f (...)', e.g. '(... ->* f) (...)'
make[2]: *** [CMakeFiles/some_ann_library.dir/main/cpp/some_ann.cc.o] Error 1
make[1]: *** [CMakeFiles/some_ann_library.dir/all] Error 2
make: *** [all] Error 2

最佳答案

不要更改搜索,传递绑定(bind)表达式:

auto& solution = cg.search(space, std::bind(
    &MyType::member_function, &myInstance, std::placeholders::_1));

关于c++ - 全局函数和非静态成员函数指针设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16836986/

相关文章:

c++ - Arduino SIM800L : converting String to char* error

c++ - C++如何获取文本框的值?

c++ - 是否可以在没有模板的情况下创建一个简单的智能指针基类?

c++ - 避免打开模板参数

c++ - haar 训练 OpenCV 断言失败

c++ - 我在哪里放置我的 MFC 程序的逻辑?

c++ - 函数声明中带有 [ ] 运算符的指针 - 这是什么意思?

excel - 在 Excel 中使用 VBA 从 PowerPoint 模板创建新的 PowerPoint 演示文稿

c++ - 为什么 const char[] 的类型推导与 const char * 不同?

c++ - 如何从更基本的同步原语制作多读/单写锁?