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