2016-08-16 6 views
1

Я читал сообщение в блоге на Anthony Williams website, когда я как-то бродил на примере его библиотеки :: thread, его barber shop example.Как работает этот шаблон?

В ней он имеет ряд через структуры, которые не унаследовать от всего:

struct start_haircut {}; 
struct no_room {}; 
struct shop_closed {}; 

Он имеет receive функцию, что цепи .match() шаблон к:

jss::actor::receive() 
    .match<start_haircut>(
     [&](start_haircut){ 
      //... 
     }) 
    .match<no_room>(
     [&](no_room){ 
      //... 
     }) 
    .match<shop_closed>(
     [&](shop_closed) 
     { 
      //... 
     }); 

Функция receive возвращает объект unspecified_message_receiver, который указывает тип (shop_closed и т. д.) и обработчик лямбда.

Что входит в функции receive и match? Как взаимодействуют функции receive и match?

Это интересный шаблон, который может иметь приложения за пределами модели потоковой передачи, в которой он используется. Меня это интересует для связи через tcp между датчиками, где переносятся небольшие пакеты сообщений и небольшие объемы данных.

+6

Похоже, что некоторые формы отправки тегов. Кроме того, я бы сказал, что это скорее «шаблон реализации», чем «шаблон дизайна». –

+0

Если есть лучший тег, тогда не стесняйтесь его менять. –

ответ

0

Вот один из способов достижения этого, будьте осторожны, поскольку, поскольку он использует информацию о времени выполнения, а не информацию времени компиляции для достижения этого, возможно, это не так, что маг шаблона C++ достигнет решения :)!
godbolt link: https://godbolt.org/g/yZC8sM
Вы можете попробовать это, используя идеон.

#include <typeinfo> 
#include <map> 
#include <memory> 
#include <functional> 
#include <iostream> 

struct Erased { 
    virtual ~Erased(){}; 
}; 

template <typename T> 
struct Handler : public Erased { 
    std::function<void(T)> handl; 
}; 

struct cont { 

    template<typename T> 
    void handle(T msg) { 
    const std::type_info *t = &typeid(T); 
    auto iter = handlers.find(t); 
    if(iter != handlers.end()) { 

     dynamic_cast<Handler<T>*>(iter->second.get())->handl(msg); 
    } 
    } 

    template <typename T> 
    void match(std::function<void (T)> handler) { 
    auto realHandler = std::make_shared<Handler<T>>(); 
    realHandler->handl = handler; 
    const std::type_info* t = &typeid(T); 
    handlers.insert(std::make_pair(t, realHandler)); 
    } 

    std::map<const std::type_info*, std::shared_ptr<Erased>> handlers; 


}; 

int main() { 
    cont container; 
    container.match<int>([](int x) { std::cout << " got avalue of ... " << x; }); 
    container.handle(5);   
} 

Просто хотел, чтобы заполнить на мой ответ здесь:
Что я уже писал выше, является решением с использованием данных во время выполнения, чтобы сделать эту рассылку (гораздо проще понять), однако вы можете создайте такую ​​отправку, используя диспетчеров времени компиляции без std :: map. небольшие заметки, как -

Вам нужно создать специальный тип для каждой цепи, которая является: .match([](int&) { ...}).match([](double&) {. .. });, где каждый матч будет создать совершенно новый тип с несколькими методами, то с помощью типа стирания вы получите общий вид, на котором вы может сделать виртуальную отправку на этот стертый тип - а затем с помощью созданного шаблоном кода вызывать нужный обработчик.

1

Это выглядит (неудивительно), как Эрланг.

Это довольно четко описано в документации, к которой вы привязались, и цитируется.

Приемная функция возвращает unspecified_message_receiver объект

так jss::actor::receive() является unspecified_message_receiver,

Calling match() на приемнике добавляет указанный MsgType в список обрабатываемых сообщений, а также регистрирует указанный обработчик, вызываемый при получении сообщения этого типа.

так

.match<start_haircut>(
    [&](start_haircut){ 
     //... 
    }) 

регистрирует лямбда обрабатывать сообщения типа start_haircut в приемник возвращается ранее.
Поскольку каждый match возвращает приемник сообщений, вы можете связать их, чтобы зарегистрировать больше обработчиков.

Я не уверен, что еще можно сказать, уточнить, но более реалистичное использование может использовать некоторые виды, которые несут какую-то полезную нагрузку, такие как

struct start_haircut { enum { Long, Short, Shaved } style; }; 

jss::actor::receive() 
    .match<start_haircut>(
     [&](start_haircut cut){ 
      switch (cut.style) 
      { 
       case start_haircut::Long: 
       // ... 
      } 
     }) 
    .match<no_room>(
     [&](no_room){ 
      //... 
     }) 
    .match<shop_closed>(
     [&](shop_closed) 
     { 
      //... 
     }); 

(Этот вид интерфейса, вероятно, делает более если вы заглядываете в учебник Erlang, например, "Learn you some Erlang for great good!").

+0

Я вижу, что вы можете подключить больше типов, и я думал о полезных нагрузках для коммуникаций. Мое основное внимание уделяется возврату 'unspecified_message_receiver', поскольку ни один объект не получает этого и, кажется, не проходит, как он возвращается. Как выглядит внутренняя часть матча? Я читал на tag_dispatch, как предлагалось @kerrek_sb. –

+0

@ graham.reeds Внутренняя часть библиотеки стоит минимум 150 фунтов стерлингов, и вы не найдете никого, разместившего их здесь. В C++ есть и другие актерские реализации, поэтому вы можете посмотреть вокруг. – molbdnilo

+0

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

Смежные вопросы