Поскольку другие упомянули шаблон посетителей, здесь приведен небольшой поворот с использованием Boost.Variant . Эта библиотека часто является хорошим выбором (или, по крайней мере, для меня), когда вам нужен набор различных поведений, основанных на значении. По сравнению с void*
он обладает преимуществом статической проверки типов: если вы напишите класс посетителя, который пропустит один из случаев, ваш код не скомпилирует , а не завершится с ошибкой во время выполнения.
Шаг 1: Определить типы сообщений:
struct EVENT_EXIT { }; // just a tag, really
struct EVENT_PLAYER_CHAT { Player * p; std::string msg; };
typedef boost::variant<EVENT_EXIT,
EVENT_PLAYER_CHAT> event;
Шаг 2: Определить посетителя:
struct event_handler : public boost::static_visitor<void> {
void operator()(EVENT_EXIT const& e) {
// handle exit event here
}
void operator()(EVENT_PLAYER_CHAT const& e) {
// handle chat event here
std::cout << e.msg << std::endl;
}
};
Это определяет обработчик события, который красиво выделяет код для каждого типа события. Наличие всех перегрузок operator()
проверяется во время компиляции (при создании экземпляра шаблона), поэтому , если вы добавите тип события позже, компилятор заставит вас добавить соответствующий код обработчика .
Обратите внимание, что event_handler
подклассы boost::static_visitor<void>
. Это определяет тип возврата для каждой из operator()
перегрузок.
Шаг 3: Используйте ваш обработчик событий:
event_handler handler;
// ...
event const& e = get_event(); //variant type
boost::apply_visitor(handler, e); // will not compile unless handler
// implements operator() for each
// kind of event
Здесь apply_visitor
вызовет соответствующую перегрузку для «фактического» значения e
. Например, если мы определим get_event
следующим образом:
event get_event() {
return EXIT_EVENT();
}
Тогда возвращаемое значение будет неявно преобразовано в event(EXIT_EVENT())
. Тогда apply_visitor
вызовет соответствующую operator()(EXIT_EVENT const&)
перегрузку.