简体   繁体   English

使用std :: bind将类成员函数注册为函数的回调

[英]Registering a class member function as a callback to a function using std::bind

I'm trying to register a class member function as a (regular) callback function. 我试图将一个类成员函数注册为(常规)回调函数。 Unless I've misunderstood something, this should be possible using std::bind (using C++11). 除非我误解了某些内容,否则应该可以使用std :: bind(使用C ++ 11)来实现。 I do this the following way: 我通过以下方式执行此操作:

std::function<void (GLFWwindow*, unsigned int)> cb = std::bind(&InputManager::charInputCallback, this, std::placeholders::_1, std::placeholders::_2);

My callback function is defined in the following way: 我的回调函数是通过以下方式定义的:

void InputManager::charInputCallback(GLFWwindow* window, unsigned int key)

I'm able to test cb immediately after creating using random data: 使用随机数据创建后,我可以立即测试cb

cb(NULL, 0x62);

I can confirm that this data is sent correctly to the callback function by printing to the terminal from within it. 我可以通过从其中打印到终端来确认此数据已正确发送到回调函数。

However, I want to register this function to GLFW so that the keypresses of the program window gets sent to the callback function. 但是,我想将此函数注册到GLFW,以便程序窗口的按键被发送到回调函数。 I do that like this: 我这样做是这样的:

glfwSetCharCallback(window, (GLFWcharfun) &cb);

Like I said before: calling it manually works just fine. 就像我之前说过的:手动调用它就可以了。 When I register it as a callback though, I get a segmentation fault whenever I press a key and GLFW tries to call the callback function. 但是,当我将其注册为回调函数时,每当我按下一个键并且GLFW尝试调用回调函数时,都会出现分段错误。

Is std::bind not what I'm looking for? std :: bind不是我要的内容吗? Am I using it incorrectly? 我使用不正确吗?

Edit: I don't think this question is a duplicate of How can I pass a class member function as a callback? 编辑:我不认为这个问题是重复的, 我该如何传递类成员函数作为回调? like it has been identified as. 就像它已经被确定为一样。 While we're adressing the same problem, I'm asking about this particular solution, using std::bind, which is only mentioned but never explained in one of the answers to the other question. 当我们解决相同的问题时,我在问使用std :: bind的特定解决方案,该问题仅在其他问题的答案之一中提及,但从未提及。

Here is the function declaration: 这是函数声明:

GLFWcharfun glfwSetCharCallback (   GLFWwindow *    window,
                                    GLFWcharfun     cbfun 
                                )

Where GLFWcharfun is defined as typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int) 其中GLFWcharfun定义为typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int)

There is an obvious problem here in that you do not get the opportunity to pass in a 'context' object which will automatically map the callback back to an instance of InputManager. 这里有一个明显的问题,就是您没有机会传递“上下文”对象,该对象会自动将回调映射回InputManager的实例。 So you will have to perform the mapping manually using the only key you have available - the window pointer. 因此,您将必须使用唯一可用的键-窗口指针来手动执行映射。

Here is one strategy... 这是一种策略...

#include <map>
#include <mutex>

struct GLFWwindow {};
typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int);

GLFWcharfun glfwSetCharCallback (   GLFWwindow *    window,
                                 GLFWcharfun    cbfun
                                 );


struct InputManager;

struct WindowToInputManager
{
    struct impl
    {
        void associate(GLFWwindow* window, InputManager* manager)
        {
            auto lock = std::unique_lock<std::mutex>(mutex_);
            mapping_[window] = manager;
        }

        void disassociate(GLFWwindow* window, InputManager* manager)
        {
            auto lock = std::unique_lock<std::mutex>(mutex_);
            mapping_.erase(window);
        }

        InputManager* find(GLFWwindow* window) const
        {
            auto lock = std::unique_lock<std::mutex>(mutex_);
            auto i = mapping_.find(window);
            if (i == mapping_.end())
                return nullptr;
            else
                return i->second;
        }

        mutable std::mutex mutex_;
        std::map<GLFWwindow*, InputManager*> mapping_;
    };

    static impl& get_impl() {
        static impl i {};
        return i;
    }

    void associate(GLFWwindow* window, InputManager* manager)
    {
        get_impl().associate(window, manager);
    }

    void disassociate(GLFWwindow* window, InputManager* manager)
    {
        get_impl().disassociate(window, manager);
    }

    InputManager* find(GLFWwindow* window)
    {
        return get_impl().find(window);
    }

};

struct InputManager
{
    void init()
    {
        // how to set up the callback?

        // first, associate the window with this input manager
        callback_mapper_.associate(window_, this);

        // now use a proxy as the callback
        glfwSetCharCallback(window_, &InputManager::handleCharCallback);

    }

    static void handleCharCallback(GLFWwindow *     window,
                           unsigned int ch)
    {
        // proxy locates the handler
        if(auto self = callback_mapper_.find(window))
        {
            self->charInputCallback(window, ch);
        }

    }

    void charInputCallback(GLFWwindow *     window,
                           int ch)
    {
        // do something here
    }


    GLFWwindow* window_;
    static WindowToInputManager callback_mapper_;    
};

Or if you prefer closures: 或者,如果您喜欢闭包:

#include <map>
#include <mutex>

struct GLFWwindow {};
typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int);

GLFWcharfun glfwSetCharCallback (   GLFWwindow *    window,
                                 GLFWcharfun    cbfun
                                 );


struct InputManager;

struct WindowToInputManager
{
    using sig_type = void (GLFWwindow *, unsigned int);
    using func_type = std::function<sig_type>;

    struct impl
    {
        void associate(GLFWwindow* window, func_type func)
        {
            auto lock = std::unique_lock<std::mutex>(mutex_);
            mapping_[window] = std::move(func);
        }

        void disassociate(GLFWwindow* window)
        {
            auto lock = std::unique_lock<std::mutex>(mutex_);
            mapping_.erase(window);
        }

        const func_type* find(GLFWwindow* window) const
        {
            auto lock = std::unique_lock<std::mutex>(mutex_);
            auto i = mapping_.find(window);
            if (i == mapping_.end())
                return nullptr;
            else
                return std::addressof(i->second);
        }

        mutable std::mutex mutex_;
        std::map<GLFWwindow*, func_type> mapping_;
    };

    static impl& get_impl() {
        static impl i {};
        return i;
    }

    template<class F>
    void associate(GLFWwindow* window, F&& f)
    {
        get_impl().associate(window, std::forward<F>(f));
        glfwSetCharCallback(window, &WindowToInputManager::handleCharCallback);
    }

    void disassociate(GLFWwindow* window)
    {
        // call whatever is the reverse of glfwSetCharCallback here
        //

        // then remove from the map
        get_impl().disassociate(window);
    }

    const func_type* find(GLFWwindow* window)
    {
        return get_impl().find(window);
    }

    static void handleCharCallback(GLFWwindow* w, unsigned int ch)
    {
        auto f = get_impl().find(w);
        // note - possible race here if handler calls disasociate. better to return a copy of the function?
        if (f) {
            (*f)(w, ch);
        }
    }

};

struct InputManager
{
    void init()
    {
        callback_mapper_.associate(window_, [this](auto* window, int ch) { this->charInputCallback(window, ch); });

    }

    void charInputCallback(GLFWwindow * window,
                           int ch)
    {
        // do something here
    }


    GLFWwindow* window_;
    WindowToInputManager callback_mapper_;

};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在类成员中使用std :: bind和std :: function会导致回调使用旧对象引用? - Using std::bind and std::function with a class member causes the callback to use an old object reference? std :: bind类成员函数 - std::bind of class member function 如何使用std :: bind将成员函数设置为回调 - How to set a member function as callback using std::bind 类成员函数使用boost :: bind和boost :: function作为回调函数 - Class member function as callback using boost::bind and boost::function 使用 std::function 作为类成员创建回调 - Creating a callback with std::function as class-member std ::绑定类中的静态成员函数 - std::bind a static member function inside the class 我怎样`std :: bind`一个非静态类成员到Win32回调函数`WNDPROC`? - How do I `std::bind` a non-static class member to a Win32 callback function `WNDPROC`? 使用类成员函数作为回调 - Using class member function as Callback 如何通过使用类的 std::bind 成员函数作为线程门户函数转换为“C”格式? - how to convert to "C" format by using std::bind member function of a class as a thread portal function? 使用 std::thread &amp; std::bind 在成员 function 中启动线程 - Start thread within member function using std::thread & std::bind
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM