std :: bind为void *到std :: function

时间:2018-09-16 22:35:57

标签: c++ c++11 void-pointers std-function stdbind

我正在尝试建立一个事件系统 该系统的用户必须执行此操作才能为输入添加事件,例如:

addEventHandler(Event::KEYBOARD_INPUT, reinterpret_cast<void*>(&std::bind(&Game::On_Input, this)));

事件触发时将调用传递的函数,这些函数存储在std :: vectors中,直到现在都没有问题。但是对于不同的事件有不同的函数签名。 而且由于std :: function本身就是类型,所以我不能让此函数接受所有尝试将std :: bind转换为void *然后将其转换回std :: function的事件,但是由于impl未定义,因此无法正常工作(0xCCCCCCCCCC)

当前代码:

void EventManager::addEventHandler(Event event, void* p_Fun)
{
    if (event == Event::KEYBOARD_INPUT) {
        m_InputCallbacks.push_back(*reinterpret_cast<std::function<void(Keycode, unsigned int)>*>(p_Fun));
    }
    /*else if(...){ // other events other push backs in other vectors

    }*/
}

和存储的函数以这种方式调用:

void EventManager::HandleEvents(SDL_Event& Event)
{
    while (PollEvent(&Event) != 0) {
        if (Event.type == KEYDOWN || Event.type == KEYUP) {
            //On_Input(Event.key.keysym.sym, Event.type);
            for (auto inputCallbackFunc : m_InputCallbacks) {
                inputCallbackFunc(Event.key.keysym.sym, Event.type);//CRASH HERE!
            }
        }
    }
}

请注意,此版本仅处理输入,我不知道将来会添加多少个事件(碰撞,多人连接等),这就是为什么我想通过addEventHandler函数自动化过程的原因检查以下内容: 1)什么是事件类型,并将void函数指针转换为该事件回调函数签名 2)将它们存储在适当的std :: vector

那么所有如何使AddEventHandler接受传递给它的每个std :: bind都可以存储并在以后调用的所有方法?

1 个答案:

答案 0 :(得分:2)

std::function提供了存储单一类型的std::vector所需要的所有类型擦除,该类型具有您将使用其签名的签名。无需强制转换为void*

为简单起见,您需要这样的东西。

#include <iostream>
#include <vector>
#include <functional>
#include <type_traits>
using namespace std;

enum Event
{
    KEYBOARD_INPUT,
    MOUSE_INPUT
};


std::vector< std::function<void(int,int)> > keyboard_handlers;
std::vector< std::function<void(int,int,int)> > mouse_handlers;



template <Event EventType,typename Func,
     typename std::enable_if<EventType==KEYBOARD_INPUT,bool>::type=true>
void addEventHandler(Func&& func)
{
keyboard_handlers.push_back(
        std::function<void(int,int)>(std::forward<Func>(func)));
}

template <Event EventType,typename Func,
     typename std::enable_if<EventType==MOUSE_INPUT,bool>::type=true>
void addEventHandler(Func&& func)
{
mouse_handlers.push_back(
        std::function<void(int,int,int)>(std::forward<Func>(func)));
}

void call_keyboard_handlers(int a,int b)
{
    for (auto inputCallbackFunc : keyboard_handlers) {
        inputCallbackFunc(a,b);
    }
}


void keyboard_callback_1(std::string name, int a , int b)
{
    std::cout << "keyboard_callback_1 " << name << " " << a << " " << b << std::endl;
}

void keyboard_callback_2(int a , int b)
{
    std::cout << "keyboard_callback_2 "  << a << " " << b << std::endl;
}

struct keyboard_callback_3_type
{
    void operator()(int a,int b)
    {
            std::cout << "keyboard_callback_3 "  << a << " " << b << std::endl;
    }
};

int main() {
    //With an extra bound in string argument.
    addEventHandler<KEYBOARD_INPUT>(std::bind(&keyboard_callback_1,"somestring",std::placeholders::_1,std::placeholders::_2));
    //From a plain function pointer 
    addEventHandler<KEYBOARD_INPUT>(&keyboard_callback_2);

    //From a memberfunction pointer
    keyboard_callback_3_type keyboard_callback_3;
    addEventHandler<KEYBOARD_INPUT>(std::bind(&keyboard_callback_3_type::operator(),&keyboard_callback_3,std::placeholders::_1,std::placeholders::_2));

    //From a non capturing lambda
    addEventHandler<KEYBOARD_INPUT>([](int a,int b){ std::cout << "lambda_callback " << a << " " <<  b <<std::endl;});

    std::string capture = "Captured";
    //From a capturing lambda
    addEventHandler<KEYBOARD_INPUT>([&](int a,int b){ std::cout << "lambda_callback " << capture << " " << a << " " <<  b <<std::endl;});


    call_keyboard_handlers(10,20);

    return 0;
}

Demo

注意,如果要将函数名称保留为addEventHandler,则必须基于事件类型启用该函数的不同变体(如示例中所示),或以不同的方式命名它们(即addKeyboardEventHandler,addMouseEventHandler等)。