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

Posted

技术标签:

【中文标题】如何将类成员函数传递给 3rd 方库中的方法?【英文标题】:How to pass class member functions to a method in a 3rd party library? 【发布时间】:2012-04-03 16:14:18 【问题描述】:

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

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 类,是否有可能实现我正在尝试的目标?

【问题讨论】:

看看boost::bind 您能否提供更多信息,具体说明它将如何帮助我解决所描述的问题。 【参考方案1】:

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

你能做的最好的(AFAIK)就是定义三个函数

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

并设置这些函数可以访问的全局变量。例如:

DataPlusFunctions* g = NULL;

particle<Space> Init(rng* r)

  // g==NULL handling omitted
  return g->fInitialise(r);

// similarly for the others

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

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

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

【讨论】:

这对我的要求不起作用,因为 moveset 的实例作为输入参数传递给 Sampler 对象,然后在远离我的引擎盖下继续调用各种函数已传递给 moveset。 为什么会阻止它工作?传递给moveset 的函数指针仍然可以在它们经过/经过的任何地方使用,并且一旦进入函数(例如Init()),您就可以访问全局。如果采样器被存储并稍后调用,它可能会阻止您更改全局。是这个问题吗? 可能是的...我可能很想随着时间的推移改变全局。 那么我认为你不走运:传递给第 3 方调用的函数没有上下文来确定在执行时要使用什么对象。设计该库的人显然不认为任何人都想做依赖于上下文的计算——如果你可以传递函子,那就太简单了...... 如果您知道存储在 Sampler 中的函数以特定顺序和已知(即可由您计算)时间调用?【参考方案2】:

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

【讨论】:

【参考方案3】:

由于您要求澄清我的评论,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();

【讨论】:

以上是关于如何将类成员函数传递给 3rd 方库中的方法?的主要内容,如果未能解决你的问题,请参考以下文章

我可以将类引用作为参数传递给 VB Net 中的函数吗?

如何将带有 args 的成员函数作为参数传递给另一个成员函数?

是否可以直接将依赖于实例的成员函数(方法)从另一个成员函数传递给 STL 的算法?

将非静态成员函数作为参数传递给另一个类中的成员函数

如何将类方法作为参数传递给该类外部的函数?

JavaScript:如何将多个参数传递给对象成员内的回调函数?