создать хэш-карту строки в вектор функций

Я реализую простую систему событий в C ++. Система предназначена для идентификации событий на основе строки (имени события), а затем при вызове события вызывать список функций обратного вызова. вот простой план:

class EventManager:
public:
register_event(string name) // creates a new entry in the event table
register_listener(string name, callback) // adds the callback to name's entry in the event table
fire_event(string name// executes all functions in the event table entry for name
private:
hashmap<string, vector<function>> //the event table

В настоящее время я борюсь с тем, как создать хэш-карту строк для векторов функций, а затем перебрать эти функции для их выполнения. Вы можете предположить, что каждый обратный вызов знает свои собственные типы функций, поэтому каждый обратный вызов будет иметь аргументы (void* userdata, ...) и я буду управлять управлением va_list в обратном вызове.

если кто-то может дать мне быстрый фрагмент, который показывает, как создать хэш-карту, и один для того, как циклически вызывать функции, это было бы полезно.

РЕДАКТИРОВАТЬ Используя ответ Юсселеса, я теперь получаю следующие ошибки:

EventManager.h

#include <string>
#include <unordered_map>
#include <vector>

using namespace std;

typedef unordered_map<string, vector<function<void()>>> CallbackMap;

class EventManager{
public:
EventManager(){
callbacks = CallbackMap();
}

void EventManager::RegisterEvent(string const& name);
void EventManager::RegisterListener(string const &name, function<void()> callback);
void EventManager::FireEvent(string name);
private:
CallbackMap callbacks;
};

EventManager.cpp

#include "EventManager.h"#include <string>

using namespace std;

void EventManager::RegisterEvent(string const& name){
callbacks[name] = NULL;
}

void EventManager::RegisterListener(string const &name, function<void()> callback)
{
callbacks[name].push_back(callback);
}

bool EventManager::FireEvent(string name){
auto event_callbacks = callbacks.find(event_name);
if (event_callbacks == callbacks.end()){
return false; // ?
}

// or std::for_each
for (auto cb = event_callbacks->second.begin();
cb != event_callbacks->second.end(); ++cb)
{
(*cb)();
}
return true;
}

Терминал

$ g++ EventManager.cpp -std=c++0x
In file included from EventManager.cpp:1:0:
EventManager.h:7:38: error: ‘function’ was not declared in this scope
EventManager.h:7:52: error: template argument 1 is invalid
EventManager.h:7:52: error: template argument 2 is invalid
EventManager.h:7:53: error: template argument 2 is invalid
EventManager.h:7:53: error: template argument 5 is invalid
EventManager.h:7:55: error: expected unqualified-id before ‘>’ token
EventManager.h:11:5: error: ‘CallbackMap’ does not name a type
EventManager.h:18:47: error: ‘function’ has not been declared
EventManager.h:18:55: error: expected ‘,’ or ‘...’ before ‘<’ token
EventManager.h: In constructor ‘EventManager::EventManager()’:
EventManager.h:14:9: error: ‘callbacks’ was not declared in this scope
EventManager.h:14:33: error: ‘CallbackMap’ was not declared in this scope
EventManager.cpp: In member function ‘void EventManager::RegisterEvent(const string&)’:
EventManager.cpp:7:5: error: ‘callbacks’ was not declared in this scope
EventManager.cpp: At global scope:
EventManager.cpp:10:57: error: ‘function’ has not been declared
EventManager.cpp:10:65: error: expected ‘,’ or ‘...’ before ‘<’ token
EventManager.cpp: In member function ‘void EventManager::RegisterListener(const string&, int)’:
EventManager.cpp:12:5: error: ‘callbacks’ was not declared in this scope
EventManager.cpp:12:31: error: ‘callback’ was not declared in this scope
EventManager.cpp: At global scope:
EventManager.cpp:15:6: error: prototype for ‘bool EventManager::FireEvent(std::string)’ does not match any in class ‘EventManager’
EventManager.h:19:10: error: candidate is: void EventManager::FireEvent(std::string)

2

Решение

HashMap строк для векторов функций …

typedef unordered_map<string, vector<function<void()>>> CallbackMap;

слова были все там. Обратите внимание, что вы могли бы использовать unordered_multimap вместо хэш-карты векторов, и function Тип отражает ваш интерфейс обратного вызова (вы можете захотеть function<void(Event*)> или что-то, например).

Как отметил Рам в комментарии, map а также multimap являются эквивалентными ассоциативными контейнерами на основе дерева, если вам конкретно не нужен хеш (или у вас нет C ++ 11, хотя вы также можете использовать boost :: unordered_map).

… и один о том, как перебрать вызов функций …

bool EventManager::fire_event(string const& event_name)
{
auto event_callbacks = callbacks.find(event_name);
if (event_callbacks == callbacks.end()) return false; // ?

// or std::for_each
for (auto cb = event_callbacks->second.begin();
cb != event_callbacks->second.end(); ++cb)
{
(*cb)();
}
return true;
}

О, и зарегистрироваться так же просто, как:

void EventManager::register_listener(string const &name,
function<void()> callback)
{
callbacks[name].push_back(callback);
}

(Я позволяю ему создавать запись о событии лениво и по запросу).

3

Другие решения

Что-то вроде:?

typedef void(*ExampleFunction) (std::string str, int bar);

void foo(std::string str, int bar){
}
void foo2(std::string str, int bar){
}

int main(){
std::map<std::string,std::vector<ExampleFunction> > f_map;
std::vector<ExampleFunction> v_func;
v_func.push_back(foo);
v_func.push_back(foo2);

f_map["tiny"] = v_func;
f_map["tiny"][0]("Woo",1);
return 1;
}
0

Если C ++ 11 является опцией (VS2012, последние версии gcc), вы можете получить хэш-карту через библиотеку C ++:

#include <unordered_map>

std::unordered_map<KeyType, ValueType> map {{x,y},{n,m1},{a,b}};
map[x] = y;
ValueType q = map[y];

и так далее. Разница между std::unordered_map а также std::map в том, что std::map сортируется, и поэтому использует красные черные деревья под. Это на самом деле может быть достаточно эффективным для ваших нужд, и в этом случае вам тоже хорошо с C ++ 03.

Обратите внимание, что я обнаружил, что MSVC ’12 не поддерживает назначение карт по умолчанию, как показывает мой пример. Если вам это нужно, используйте boost :: assign:

#include <boost/assign.hpp>

std::unordered_map<K,V> map = boost::assign::map_list_of<K,V> (x,y)(a,b)(n,q);
0

Во-первых, вам нужно определить, что такое обратный вызов. Ваши параметры в основном сводятся к указателю на функцию:

typedef void (* EventCallback)(void * userdata, ...);

Или интерфейс:

class IEventCallback
{
public:
virtual void callback(void * userdata, ...) = 0;
};

Я бы предпочел версию интерфейса — вы можете обернуть указатель функции в объект класса, реализующего этот интерфейс; гораздо сложнее пойти другим путем.

На ваше EventManagerОпределите карту и тип (для упрощения итерации):

private:
typedef std::vector<IEventCallback &> EventCallbackList_t;
typedef std::map<std::string, EventCallbackList_t> EventMap_t;

EventMap_t m_eventMap;

Далее реализация довольно проста:

void EventManager::register_event(std::string const & name)
{
m_eventMap.insert(std::make_pair(name, EventCallbackList_t()));
}

void EventManager::register_listener(std::string const & name, IEventCallback & callback)
{
EventMap_t::iterator event = m_eventMap.find(name);

if (event == m_eventMap.end()) {
throw "No such event.";
}

event->second.push_back(callback);
}

void EventManager::fire_event(std::string const & name, void * userdata, ...)
{
EventMap_t::iterator event = m_eventMap.find(name);

if (event == m_eventMap.end()) {
throw "No such event.";
}

for (EventCallbackList_t i = event->second.begin(); i != event->second.end(); ++i) {
i->callback(userdata, ...);
}
}

Есть еще несколько проблем с этой реализацией, которые я оставлю на ваше усмотрение:

  • Параллелизм. Убедитесь, что операции регистрации / запуска синхронизированы, если они будут вызываться из нескольких потоков.
  • Владение объектом обратного вызова. Рассмотрите возможность использования типа общего указателя для управления временем их жизни.
0
По вопросам рекламы [email protected]