2013-05-30 139 views
2

我有一个连续优化算法,它将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函数的模板声明和实现更改为全局函数或非静态成员函数?另一种方法是创建一个全局包装函数,并使用可变参数将参数传递给包装函数,但这是丑陋的,而不是类型安全的。

更新:这个例子使用了下面答案的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 

回答

3

不要更改搜索,通过绑定表达式:

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

绑定将工作得很好 – count0

+0

一边注意的是,此工作我需要C11,我目前不在。我在GNU MacPorts上gcc46 4.6.3_9 –

+0

4.6的-std = C++ 0x模式没有std :: bind? –

相关问题