2012-04-03 3 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つのグローバル関数を定義するよりも、私は、入力引数が存在しないとして、私は渡すことはできません明らかにされ、様々な追加の情報を知るために各機能を必要とします。この問題をさらに複雑にするために、私はこのmoveetオブジェクトのいくつかの異なるインスタンスを作成したいと思います。それぞれ、同じ関数を使用したいのですが、基礎となる異なるデータにします。

私の考えは

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

+0

説明したように問題を解決する方法を具体的にどのように説明すればよいでしょうか。 – oracle3001

+0

下記の私の答えを参照してください – Chad

答えて

0

これを解決するために、いわゆるthunksオブジェクトを使用できます。一般的な考え方は、実行時にポインタが必要な関数を生成することです。 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の値を設定します。

利点は、状態情報を格納するために使用できるオブジェクトがあり、ポインティング先のオブジェクトを別のインターフェイス(インターフェイスを使用している場合もある)に置き換えることができ、動的な動作を提供できることです。

グローバル設定が2つのスレッドによって同時に変更される可能性があるため、この設定を並列設定で使用する場合は問題です。この場合は、mutexまたはロックで保護することができます。

+0

これは私が必要とするものでは機能しません。ムービーセットのインスタンスがSamplerオブジェクトの入力引数として渡されるため、私の外にあるボンネットの下が、 moveetに渡されました。 – oracle3001

+0

なぜそれが機能しないのでしょうか? 'moveset'に渡された関数ポインタは、それらが移動/通過し、関数の中で(例えば' Init() ')どこでも使用可能であり、グローバルにアクセスできます。サンプラーが保存され、後で呼び出されると、グローバルが変更されないことがあります。それは問題ですか? – Attila

+0

それははいかもしれません...私はよく時間をかけてグローバルを変更したいかもしれません。 – oracle3001

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(); 
} 
関連する問題