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



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

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端发布相同的主题。

这就是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);
}

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

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);

最新更新