2016-09-27 2 views
0

私のプロジェクトではGLFW3を使用しています。そして、私は、関数GLFWSetKeyCallbackにC++ 11ラムダを与えようとしています。これはパラメータとしてGFLWwindowをとり、GLFWfunkey関数はtypedefです。 void(* GLFWkeyfun)(GLFWwindow *、int、int、int、 int)。ラムダをGLFWkeyfunとして使用

機能が私のWindowクラスから呼び出され、ここでコード

window.hpp

class Window 
{ 
     public: 
       Window(GLuint width, GLuint height, std::string title); 
       ~Window(); 

       GLFWwindow* get() { return window_.get(); } 
       bool is_open() { return open_; }; 
       void close(); 

     private: 
       bool open_ = false; 
       std::unique_ptr<GLFWwindow, DestroyWindow> window_; 
       std::vector<Drawable*> drawables_; 
}; 

そしてwindow.cpp

#include <pck/window.hpp> 

Window::Window(GLuint width, GLuint height, std::string title) : 
     open_(true) 
{ 
     window_.reset(glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr)); 
    glfwMakeContextCurrent(window_.get()); 

     Global::width = width; 
     Global::height = height; 

     glfwSetKeyCallback(window_.get(), [this](GLFWwindow* window, int key, int scancode, int action, int mode){ 
       for(auto it : drawables_) 
         it->input(window, key, scancode, action, mode); 
     }); 
} 

Window::~Window() 
{ 
     window_.reset(); 
} 

void 
Window::close() 
{ 
     open_ = false; 
     window_.reset(); 
} 

とコンパイラ(打ち鳴らす++ 3.8からの誤差があります.1)

fatal error: no matching function for call to 'glfwSetKeyCallback' 
     glfwSetKeyCallback(window_.get(), [this](GLFWwindow* window, i... 
     ^~~~~~~~~~~~~~~~~~ 
/usr/include/GLFW/glfw3.h:3307:20: note: candidate function not viable: no 
     known conversion from '(lambda at 
     /path/to/file.cpp)' to 
     'GLFWkeyfun' (aka 'void (*)(GLFWwindow *, int, int, int, int)') for 2nd argument 
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); 

誰かが私が間違っていたことを私に指摘できますか?

ありがとうございます!

+0

は役に立つかもしれませんします。http://stackoverflow.com/a/39622958/434551。 –

答えて

3

空のキャプチャリストを持つlambdasは、単純な古い関数ポインタに変換可能です。

ので、問題は

[this] 

代わりの

[] 

あるしかし、あなたはステートフルコールバックが必要な場合、あなたは運の出ています。私が言う限りでは、これは可能ではありません、とにかく悪い体操なしではありません。

言われているように、ほとんどのC APIは、コールバックが実際に動作するはずの状態を受け取れるようにするコンテキストポインタを提供します。あなたの例ではwindowのパラメータがそうであるようです。

+0

私のラムダでコードを隠すようなものですが、短いストーリー、関数呼び出しはクラスの中にあり、私はラムダで何をしているのか 'this'が必要です – Bl4ckb0ne

+0

最初の投稿を編集して – Bl4ckb0ne

+0

私はGLFW3を知らないのですが、通常はコールバック関数に 'context'パラメータを与えて、フリーな関数(あるいはフリー関数へのポインタとして偽装されたラムダ)を使ってコンテキストを使用できるようにしています。 )。 'window'パラメータはそれではありませんか? – krzaq

1

krzaqは、関数ポインタが必要な場合はクロージャを使用できないと述べています。したがって、例のようにthisをキャプチャしてはいけません。

とにかくthisが必要な場合は、GLFWwindowと関連付けてください。このAPIを使用することができます:glfwSetWindowUserPointer GLFWwowowインスタンスとWindowクラスのインスタンスを関連付けることができます。コールバック内では、glfwGetWindowUserPointerで検索できます。

だからあなたのコードは、(擬似コード)のようになります。

glfwSetWindowUserPointer(window_.get(), this); 
glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){ 
       Window* pw = (Window*)glfwGetWindowUserPointer(window); 
       for(auto it : pw->drawables_) 
         it->input(window, key, scancode, action, mode); 
     }); 
0

関数ポインタに変換することができないのキャプチャを持つラムダを。関数ポインタはステートレスで、関数を指します。キャプチャしたラムダには状態があります。それはオブジェクトのように振る舞います。メンバ関数は、インスタンスなしでは呼び出すことができません。それはキャプチャを持つラムダを関数ポインタに変換できない方法です。

あなたはそれにあなたの関数を変更する必要があります:

glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){ /* ... */ }); 

しかし、あなたはこれを利用することができないのこの制限を回避することができます。 GLFWは私たちに州を渡す方法を与えました。構造体GLFWWindowには、自由に変更してアクセスできるメンバーvoid*が含まれています。あなたは何ができるか

次のようなものされています

// Here we are setting the user pointer to `this` 
glfwSetWindowUserPointer(window_.get(), this); 

glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){ 
    // Here we retrieve the pointer we setted before. It will be equal to `this` 
    auto& self = *static_cast<Window*>(glfwGetWindowUserPointer(window)); 
    for(auto&& it : self.drawables_) { 
     it->input(window, key, scancode, action, mode); 
    } 
}); 
+0

いいですね、でも、 'Window'クラスはGLFWwowowクラスを包むラッパーなので、これはうまくいきません。 – Bl4ckb0ne

+1

どうしたの?任意のオブジェクトをユーザーポインタの内側に配置できます。自分のものを含め、あなたのラッパーを含めて。それはそれをコピーしません。実際の 'this'にポインタを割り当てるだけです。ユーザーポインタは、その目的のためだけに存在します。外部状態にアクセスできるようにポインタを設定します。あなたのケースでは、その状態がラッパーになります。 –

+0

私はこの文書を見ました、ありがとう。私は後でそれを試し、あなたにフィードバックを与えます – Bl4ckb0ne

関連する問題