簡體   English   中英

使用std :: bind將類成員函數注冊為函數的回調

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

我試圖將一個類成員函數注冊為(常規)回調函數。 除非我誤解了某些內容,否則應該可以使用std :: bind(使用C ++ 11)來實現。 我通過以下方式執行此操作:

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

我的回調函數是通過以下方式定義的:

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

使用隨機數據創建后,我可以立即測試cb

cb(NULL, 0x62);

我可以通過從其中打印到終端來確認此數據已正確發送到回調函數。

但是,我想將此函數注冊到GLFW,以便程序窗口的按鍵被發送到回調函數。 我這樣做是這樣的:

glfwSetCharCallback(window, (GLFWcharfun) &cb);

就像我之前說過的:手動調用它就可以了。 但是,當我將其注冊為回調函數時,每當我按下一個鍵並且GLFW嘗試調用回調函數時,都會出現分段錯誤。

std :: bind不是我要的內容嗎? 我使用不正確嗎?

編輯:我不認為這個問題是重復的, 我該如何傳遞類成員函數作為回調? 就像它已經被確定為一樣。 當我們解決相同的問題時,我在問使用std :: bind的特定解決方案,該問題僅在其他問題的答案之一中提及,但從未提及。

這是函數聲明:

GLFWcharfun glfwSetCharCallback (   GLFWwindow *    window,
                                    GLFWcharfun     cbfun 
                                )

其中GLFWcharfun定義為typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int)

這里有一個明顯的問題,就是您沒有機會傳遞“上下文”對象,該對象會自動將回調映射回InputManager的實例。 因此,您將必須使用唯一可用的鍵-窗口指針來手動執行映射。

這是一種策略...

#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_;    
};

或者,如果您喜歡閉包:

#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM