Но просто вызывать функцию wait()
особого смысла не имеет — как правило, нам нужно обработать полученное сообщение. Для этого предназначена функция-член handle()
(3). Это шаблон, и тип сообщения нельзя вывести, поэтому необходимо явно указать, сообщение какого типа обрабатывается, и передать функцию (или допускающий вызов объект) для его обработки. Сама функция handle()
передает очередь, текущий объект dispatcher
и функцию-обработчик новому экземпляру шаблонного класса TemplateDispatcher
, который обрабатывает сообщения указанного типа. Код этого класса показан в листинге С.5. Именно поэтому мы проверяем флаг chained
в деструкторе перед тем, как приступить к ожиданию сообщения; он не только предотвращает ожидание объектами, содержимое которых перемещено, но и позволяет передать ответственность за ожидание новому экземпляру TemplateDispatcher
.
Листинг С.5. Шаблон класса TemplateDispatcher
namespace messaging {
template<
typename PreviousDispatcher, typename Msg, typename Func>
class TemplateDispatcher {
queue* q;
PreviousDispatcher* prev;
Func f;
bool chained;
TemplateDispatcher(TemplateDispatcher const&) = delete;
TemplateDispatcher& operator=(
TemplateDispatcher const&) = delete;
template<
typename Dispatcher, typename OtherMsg, typename OtherFunc>
friend class TemplateDispatcher;←┐
Все конкретизации
void wait_and_dispatch() │
TemplateDispatcher
{ │
дружат между собой
for (;;) {
auto msg = q->wait_and_pop();
if (dispatch(msg))←┐
Если мы обработали
break; │
сообщение выходим
}
(1) из цикла
}
bool dispatch(std::shared_ptr
if (wrapped_message
dynamic_cast
msg.get())) { ←┐
Проверяем тип
f(wrapper->contents);│
сообщения и
return true; │
вызываем
}
(2) функцию
else {
return prev->dispatch(msg);←┐
Вызываем предыдущий
}
(3) диспетчер в цепочке
}
public:
TemplateDispatcher(TemplateDispatcher&& other):
q(other.q), prev(other.prev), f(std::move(other.f)),
chained(other.chained) {
other.chained = true;
}
TemplateDispatcher(
queue* q_, PreviousDispatcher* prev_, Func&& f_):
q(q_), prev(prev_), f(std::forward
{
prev_->chained = true;
}
template
TemplateDispatcher
handle(OtherFunc&& of)←┐
Дополнительные обработчики
{
(4) можно связать в цепочку
return TemplateDispatcher<
TemplateDispatcher, OtherMsg, OtherFunc>(
q, this, std::forward
}
~TemplateDispatcher() noexcept(false)←┐
Деструктор снова
{ │
помечен как
if (!chained) {
(5) noexcept(false)
wait_and_dispatch();
}
}
};
}
Шаблон класса TemplateDispatcher<>
устроен по образцу класса dispatcher
и почти ничем не отличается от него. В частности, деструктор тоже вызывает wait_and_dispatch()
, чтобы дождаться сообщения.