这个模式是如何运作的

How does this pattern work?

本文关键字:何运作 模式      更新时间:2023-10-16

我在读Anthony Williams网站上的一篇博客文章时,无意间看到了他的just::thread库的一个例子,理发店的例子。

里面有一系列不继承任何东西的a结构:

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等)和lambda处理程序。

receivematch函数里面有什么?receivematch功能是如何相互作用的?

这是一个有趣的模式,可以在它所使用的线程模型之外拥有应用程序。我对传感器之间的tcp通信很感兴趣,其中小消息包和少量数据正在连续传输。

这看起来(毫不奇怪)像Erlang。

这在你所链接的文档中有很清楚的描述,并引用了。

receive函数返回一个unspecified_message_receiver对象

所以jss::actor::receive()unspecified_message_receiver

在接收者上调用match()将指定的MsgType添加到已处理消息列表中,并在接收到该类型消息时注册指定的处理程序。

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

在之前返回的接收器中注册lambda来处理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教程,这种接口可能会更有意义,比如"学习一些Erlang !")。

这是实现它的一种方法,但要小心,因为它使用运行时信息而不是编译时信息来实现这一点,这可能不是c++模板魔术师实现解决方案的方式:)!
godbolt链接:https://godbolt.org/g/yZC8sM
你可以使用ideone在线尝试。

#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&) {. .. });,其中每个匹配将创建一个具有多个方法的完整新类型,然后使用类型擦除,您将获得一个泛型类型,您可以对该擦除的类型进行虚拟分派-然后使用模板生成的代码调用所需的处理程序。