如何将类成员函数传递给第三方库中的方法?

时间:2012-04-03 16:14:18

标签: c++ class templates member-function-pointers

以下是我想在第三方库中使用的类的构造函数(因此不能更改此函数)。

template <class Space>
moveset<Space>::moveset(particle<Space> (*pfInit)(rng*),
          void (*pfNewMoves)(long, particle<Space> &,rng*),
          int (*pfNewMCMC)(long,particle<Space> &,rng*))

然而,我不是简单地定义3个全局函数,而是需要每个函数来知道各种额外信息,显然我无法传递,因为没有输入参数。为了进一步使问题复杂化,我想要创建这个moveset对象的几个不同实例,每个实例都希望使用相同的函数,但是在不同的底层数据上。

我的想法是按照这些方式创建一个控股类,

Class DataPlusFunctions {

 public:

   DataPlusFunctions(Data* dataPtr) { dataPtr_ = dataPtr ;}

   smc::particle<cv_state> fInitialise(smc::rng *pRng)
    {

      // the actual function will be a lot more complicated than this and
      // likely to require calling other methods / classes.
      // The Data stored in a different class will be changing...which is
      // important in relation to the pfNewMoves function.

      double value = dataPtr_->value() ;
      return smc::particle<cv_state>(value,likelihood(0,value));          

    }

    ... same for other required functions
 private:

  Data* dataPtr_ ;
}

*

Class MainClass {

...
void IK_PFController::initialise() 
{

   std::vector<DataPlusFunctions> dpfV ;

   for (int i = 0 ; i < NSAMPLERS ; i++)
        dpfV.push_back(DataPlusFunctions(&data[i])) ;


  pSamplers_ = (smc::sampler<cv_state>**)(new void* [NSAMPLERS]) ;

  for (int i = 0 ; i < NSAMPLERS ; i++) {

    // Normal way of calling function, having defined global functions e.g.
    //smc::moveset<cv_state> Moveset(fInitialise, fMove, NULL);

    // How to achieve this given my problem ??????????????
    //smc::moveset<cv_state> Moveset(&dpfV[i]::fInitialise, &dpfV[i]::fMove, NULL);

     pSamplers_[i].SetMoveSet(Moveset);

  }

} 

}

是允许的吗?如果没有,是否有可能实现我的尝试,我将能够改变moveset类?

3 个答案:

答案 0 :(得分:1)

为了调用成员函数(通过指针),您需要一个适当类型的对象。由于第三方函数需要vanilla函数指针,因此无法传递成员函数。

你能做的最好的(AFAIK)是定义三个功能

particle<Space> Init(rng*);
void NewMoves(long, particle<Space> &,rng*);
int NewMCMC(long,particle<Space> &,rng*);

并设置这些函数访问的全局变量。 e.g:

DataPlusFunctions* g = NULL;

particle<Space> Init(rng* r)
{
  // g==NULL handling omitted
  return g->fInitialise(r);
}
// similarly for the others

并在调用第三方函数之前设置g的值。

优点是你有一个可以用来存储状态信息的对象,你也可以用另一个对象替换指向对象(甚至可以使用接口),提供动态行为。

问题是如果你想在并行设置中使用它,因为全局可能会被两个线程同时更改 - 在这种情况下,你可以使用互斥锁或锁来保护它。

答案 1 :(得分:0)

您可以使用所谓的thunks对象来解决此问题。一般的想法是生成在运行时需要指针的函数。 Windows上着名的ATL库使用这种技术。有关此技术的深入讨论,包括示例代码,请参阅文章WNDPROC Thunks

答案 2 :(得分:0)

由于您要求澄清我的评论,boost::bind允许您将成员函数指针绑定到稍后要调用的对象(以及可选的某些参数)。这是一个简单的例子:

#include <boost/bind.hpp>
#include <iostream>

class Hello
{
public:
   void World()
   {
      std::cout << "Hello World.\n";
   }
};

class SomethingElse
{
public:
   void Grumble(int x)
   {
      std::cout << x << " Grumble, Grumble...\n";
   }
};


int main()
{
   Hello obj;

   // bind obj.World() to a functor that can be called later    
   auto f = boost::bind(&Hello::World, &obj);

   // example...
   f();

   SomethingElse obj2;

   // bind obj2.Grumble(13) to a functor that can be called later
   auto g = boost::bind(&SomethingElse::Grumble, obj2, 13);

   // example...
   g();
}