Как передать функции-члены класса методу в сторонней библиотеке? - PullRequest
0 голосов
/ 03 апреля 2012

Ниже приведен конструктор класса, который я хотел бы использовать в сторонней библиотеке (поэтому изменять эту функцию нельзя).

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 ]

1 голос
/ 03 апреля 2012

Чтобы вызвать функцию-член (через указатель), вам нужен объект соответствующего типа. Поскольку сторонней функции требуются указатели ванильных функций, вы не можете передать функцию-член.

Лучшее, что вы можете сделать (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 перед вызовом сторонней функции.

Преимущество заключается в том, что у вас есть объект, который вы можете использовать для хранения информации о состоянии, а также вы можете заменить указанный объект другим (возможно, даже используя интерфейс), обеспечивая динамическое поведение.

Проблема в том, что если вы хотите использовать это в параллельной настройке, так как глобальный объект может быть изменен двумя потоками одновременно - в этом случае вы можете защитить его мьютексом или блокировкой.

0 голосов
/ 04 апреля 2012

Поскольку вы попросили пояснить мой комментарий, 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();
}
0 голосов
/ 03 апреля 2012

Вы можете использовать так называемые объекты Thunks для решения этой проблемы. Общая идея состоит в том, чтобы генерировать функции, для которых вам нужны указатели во время выполнения. Знаменитая библиотека ATL в Windows использует эту технику. См. Статью WNDPROC Thunks для подробного обсуждения этого метода, включая пример кода.

...