根据输入从一种类型转换为另一种类型

时间:2020-10-21 06:36:17

标签: c++ c++17

我正在尝试在两个网络之间创建代理。我想做类似的事情:

void onMsg(std::string topic, Msg msg) {
  if (topic == "topic1") {
    InMsg1 inmsg1 = parseMsg1<InMsg1>(msg);
    OutMsg1 outmsg1 = convert(inmsg1);
    publish<OutMsg1>(topic, outmsg1);
  }
  // repeat for each message type we need to convert.

所以我不能使用模板,因为类型取决于主题。如果我可以使用以下内容创建地图并对其进行查找,那就太好了。 (我知道我不能在地图中使用类型,仅举一个例子。)

std::map<std::string, std::pair<Type1, Type2>> _map = {
  { "topic1", { InMsg1, OutMsg1 } },
  { "topic2", { InMsg2, OutMsg2 } },
  { "topic3", { InMsg3, OutMsg3 } }
}

有人有建议或至少我可以看的某种设计模式吗?

作为参考,我正在从MQTT转换为ROS消息。因此,我需要根据接收消息的主题来分析MQTT消息,然后在ROS端的同一主题上发布该消息。

2 个答案:

答案 0 :(得分:3)

std::variant的作用是:表示一组已知类型的值。

您收到的消息是std::variant<mqtt::type1, mqtt::type2, ...>。您的传出邮件是std::variant<ROS::type1, ROS::type2, ...>。从一个转换到另一个应通过std::visit完成。


using Incoming = std::variant<type1, type2, ...>;

// converting from mqtt to 'internal' type using
// template specialization
template<T> T parseMqtt(const mqttmsg &msg);
type1 parseMqtt<type1>(const mqttmsg &msg) {
  return {...};
}
type2 parseMqtt<type2>(const mqttmsg &msg) {
  return {...};
}
// dispatch using a type identifier
Incoming parseMqtt(const std::string &topic, const mqttmsg &msg) {
  ...
  if(topic == "topic 1") { return parseMqtt<type1>(msg); }
  if(topic == "topic 2") { return parseMqtt<type2>(msg); }
  ...
}

// converting from 'internal' type to ROS using
// overloads:
ros_message to_ros_msg(const type1 &msg) {
  return {...};
}
ros_message to_ros_msg(const type2 &msg) {
  return {...};
}

// bringing it all together
auto mqtt_to_ros(const std::string &topic, const mqttmsg &msg) {
  const auto &incoming = parseMqtt(topic, msg);
  const auto &outgoing = std::visit(
     [](const auto &msg) { return to_ros_msg(msg); }
     , incoming);
  ros_send(outgoing);
}

答案 1 :(得分:1)

首先,将代理逻辑提取到模板函数中:

template <class InMsg, class OutMsg>
void proxy(std::string topic, Msg msg) {
    InMsg inmsg = parseMsg<InMsg>(msg);
    OutMsg outmsg = convert<InMsg, OutMsg>(inmsg);
    publish<OutMsg>(topic, outmsg);
}

现在您可以创建一个包含处理程序的调度表:

using ProxyHandler = std::function<void(std::string, Msg)>;
std::map<std::string, ProxyHandler> handlers = {
    { "topic1", &proxy<InMsg1, OutMsg1> },
};

并像这样使用它:

auto it = handlers.find(topic);
if (it != handlers.end()) {
    (it->second)(topic, msg);
}
// or
handlers[topic](topic, msg);
相关问题