2012-04-03 78 views
0

以下是我想在第三方庫中使用的類的構造函數(因此更改此函數不是一種選擇)。如何將類成員函數傳遞給第三方庫中的方法?

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

    } 

} 

} 

是否被允許?如果沒有,是否有可能實現我所嘗試的,因爲我將能夠改變運動類課程?

+1

看看'boost :: bind'。 – Chad 2012-04-03 16:26:04

+0

請問您是否可以提供更多信息,具體說明它將如何幫助我解決所描述的問題。 – oracle3001 2012-04-03 19:46:49

+0

請參閱下面的答案 – Chad 2012-04-03 21:08:57

回答

0

你可以使用所謂的thunk對象來解決這個問題。總體思路是生成在運行時需要指針的函數。 Windows上着名的ATL庫使用這種技術。有關此技術的一些深入討論,請參見文章WNDPROC Thunks,其中包括示例代碼。

1

爲了調用成員函數(通過指針),您需要一個適當類型的對象。由於第三方功能需要香草函數指針,所以不能傳遞成員函數。

你能做的最好(據我所知)是定義三種功能

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 

並在調用第三方功能之前設置值爲g

好處是你有一個對象可以用來存儲狀態信息,你也可以用另一個替換指向對象(甚至可以使用接口),提供動態行爲。

問題是如果你想在並行設置中使用它,全局可能會被兩個線程同時改變 - 在這種情況下,你可以使用互斥鎖或鎖來保護它。

+0

這不適用於我所需要的,因爲moveset的實例將自己作爲輸入參數傳遞給採樣器對象,然後在距離我的引擎蓋下方繼續調用各種函數傳遞給moveset。 – oracle3001 2012-04-03 16:48:22

+0

爲什麼會阻止它的工作?傳遞給'moveset'的函數指針在它們傳遞/傳遞的任何地方仍然可用,並且一旦進入函數(例如'Init()'),就可以訪問全局函數。如果採樣器存儲並稍後調用,它可能會阻止您更改全局。這是問題嗎? – Attila 2012-04-03 16:51:01

+0

這可能是肯定的......我可能想要隨着時間的推移改變全球。 – oracle3001 2012-04-03 19:49:22

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(); 
} 
相關問題