2017-01-06 18 views
0

2つのコールバックオブジェクトを保持するRendererというクラスがあります。引数を指定してジェネリックコールバックをバインドするC++ 11

void (*drawCall)(const sf::Drawable& drawable, const sf::RenderStates& states); 
void (*drawPrimCall)(const sf::Vertex* vertices, unsigned int vertexCount, 
    sf::PrimitiveType type, const sf::RenderStates& states); 

私は、これらのコールバックをバインドするパブリック関数を持っていると思います、それは、このような何かテンプレートですし、その有効なパラメータを持つ2つの描画メソッドそれぞれを持つクラスが必要です。しかし

template<typename T> 
inline void setRenderer(T* instance) 
{ 
    using namespace std::placeholders; 
    drawCall = std::bind(&T::draw, instance, _1, _2); 
    drawPrimCall = std::bind(&T::draw, instance, _1, _2, _3, _4); 
} 

、あなたはこれがうまくいかないと想像するかもしれません。私はまだstd :: bindについて学習しています。プレースホルダの使用についてはわかりませんが、ここで何をしようとしているのか理解しています。

私はGoogleで回答を探してみましたが、少し難解でした。何か助けてくれてありがとうございました!

UPDATE:原因の制約にsetRenderer方法のための今すぐ

std::function<void(const sf::Drawable& drawable, const sf::RenderStates& states)> drawCall_fn; 
std::function<void(const sf::Vertex* vertices, unsigned int vertexCount, 
        sf::PrimitiveType type, const sf::RenderStates& states)> drawPrimCall_fn; 

[OK]を、@Holtによって与えられた答えは::をはstdする変更した後、働くためには、私のコールバックは次のようになり機能します外部ライブラリ私はまた関数参照を渡す必要があります。

template<typename T> 
inline void setRenderer(T* instance, void(T::*drawCall)(const sf::Drawable&, const sf::RenderStates&)) 
{ 
    using namespace std::placeholders; 
    drawCall_fn = std::bind(drawCall, instance, _1, _2); 
} 

呼び出されたとき、私はこのようにそれを行うことができますこのような:

renderer.setRenderer<sf::RenderTarget>(&window, &sf::RenderTarget::draw); 

**注:私は簡単に後に展開することができますように私は一瞬だけdrawCall_fnを扱っています。

UPDATE2:setRenderer drawCallに欠落しているパラメータを追加しました。

+1

'drawCall'と' drawPrimCall'の種類は何ですか? 'std :: function'ですか? – Holt

+0

メンバー関数ポインタを不可能な関数ポインタに変換しようとしているようです。たとえば、http://stackoverflow.com/questions/4296281/how-can-i-pass-a-member-function-to-function-pointerを参照してください。 –

+0

@Holt彼らは関数ポインタですが、私はそれらをstd :: functionにすることを検討していました。私はあなたの答えatmを試しています。 – Belfer4

答えて

2

instanceをキャプチャする(キャプチャラムダまたはstd::bindのいずれかを使用)必要があるため、関数ポインタを使用して必要な処理を行うことはできません。あなたがラムダを使用するか、またはそれらを割り当てることが&T::drawのオーバーロードの解決を強制するか、そして、

std::function<void(const sf::Drawable&, const sf::RenderStates&)> drawCall; 
std::function<void(const sf::Vertex*, unsigned int, 
    sf::PrimitiveType, const sf::RenderStates&)> drawPrimCall; 

:あなたはstd::functionを使用する必要があります

両方の場合
drawCall = [instance](const sf::Drawable& drawable, const sf::RenderStates& states) { 
    instance->draw(drawable, states); 
}); 

// Or: 
drawCall = std::bind((void (T::*)(const sf::Drawable&, const sf::RenderStates&))&T::draw, 
        instance, _1, _2); 

、あなたは再指定する必要があります引数のリストは、これを避けるために小さなヘルパー関数を使うことができます:

template <typename T, typename R, typename... Args, typename... BArgs> 
void gbind_mem(std::function<R(Args...)> &fn, R(T::*mfn)(Args...), 
       T *instance, BArgs&&... args) { 
    fn = std::bind(mfn, instance, std::forward<BArgs>(args)...); 
} 

そして、あなたは簡単に使用してバインドすることができます。

gbind_mem(drawCall, &T::draw, instance, _1, _2); 

あなたはコンパイラがdrawCallからパラメータを推定するの大変な仕事をやらせます。

+0

これは素晴らしい作品です。ありがとうございます! – Belfer4

0

...それは2つのコールバックが

"コールバックオブジェクト"のようなものは、C++ではありませんオブジェクト保持しています。おそらくあなたが探しているものはfunction pointersまたはstd::functionです。関数ポインタの場合は、あなたの構文が正しくありません - あなたは*を追加する必要があります。

void (*drawCall)(const sf::Drawable& drawable, const sf::RenderStates& states = sf::RenderStates::Default); 
void (*drawPrimCall)(const sf::Vertex* vertices, unsigned int vertexCount, sf::PrimitiveType type, 
        const sf::RenderStates& states = sf::RenderStates::Default); 

あなたは、それらを設定することができるようになります。例:

void (*callback)(int); 
void real_function(int) { } 

int main() 
{ 
    callback = &real_function; 
} 

あなたの「本当の機能」署名が一致しない場合は、コールバックの、あなたはそれを適応させるために、関数ポインタに暗黙的に変換されcaptureless lambda expressionsを、使用する必要があります。

void (*callback)(int); 
void real_function(int, float) { } 

int main() 
{ 
    callback = [](int x){ return real_function(x, 5.f); }; 
} 

wandboxに最小限の例を指定すると、より具体的な回答を得ることができます。

関連する問題