0

The following is the constructor of a class I would like to use in a 3rd party library (so altering this function isn't an option).

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

However, rather than simply defining 3 global functions, I need each of the functions to know various extra information, which obviously I can't pass as there are no input arguments. To further complicate the issue, I am going to want to make several different instances of this moveset object, each wanting to use the same functions, but upon different underlying data.

My thought is to create a holding class something along these lines,

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);

  }

} 

}

Is is allowed? If not, is it possible to achieve what I am attempting given that I will be able to alter the moveset class?

genpfault
  • 51,148
  • 11
  • 85
  • 139
oracle3001
  • 1,090
  • 19
  • 31

3 Answers3

1

In order to call a member function (via pointer), you need an object of the appropriate type. Since the 3rd party function requires vanilla function pointers, you cannot pass a member function.

The best you could do (AFAIK) is to define three functions

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

and set a global variable that those functions access. e.g.:

DataPlusFunctions* g = NULL;

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

and set the value of g before calling the 3rd party function.

The advantage is that you have an object you can use to store state info and also you can replace the pointed-to object with another (maybe even using interface), providing dynamic behavior.

The problem is if you want to use this in a parallel setting as the global might be changed by two threads simultaneously -- in this case you could protect it with a mutex or lock.

Attila
  • 28,265
  • 3
  • 46
  • 55
  • This won't work for what I require, as the instances of moveset are passed on themselves as input arguments to a Sampler object, which then underneath the bonnet away from me goes on to call the various functions that were passed to moveset. – oracle3001 Apr 03 '12 at 16:48
  • Why would that prevent it from working? The function pointers passed to `moveset` are still usable wherever they travel/passed, and once inside the function (e.g. `Init()`), you have access to the global. It might prevent you from changing the global if the Sampler is stored and called later. Is that the problem? – Attila Apr 03 '12 at 16:51
  • It could be yes...I may well want to change the global over time. – oracle3001 Apr 03 '12 at 19:49
  • Then I think you are out of luck: the functions passed to the 3rd party call do not have context to figure out what object to use at time of execution. Whoever designed that library clearly did not think anyone ever would want to do context-dependent computations -- would have been trivial if you could pass functors... – Attila Apr 03 '12 at 20:07
  • Maybe if you know that the functions stored in Sampler are called in a specific order and for known (i.e. computable by you) times? – Attila Apr 03 '12 at 20:09
0

Since you asked for clarification of my comment, boost::bind allows you to bind a member function pointer to an object (and optionally some number of parameters) to be called later. Here's a simple example:

#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();
}
Chad
  • 18,706
  • 4
  • 46
  • 63
0

You can use so-called thunks objects to solve this. The general idea is to generate the functions for which you need pointers at runtime. The famous ATL library on Windows uses this technique. See the article WNDPROC Thunks for some in-depth discussion of this technique including sample code.

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207