我有一个Message
结构,我正在使用消息总线,我想发送带有消息的数据。问题是数据的类型会有所不同;也许对于一个消息我只想发送一个int,但另一个消息我想要发送几个整数,一个字符串,甚至可能是指向一个对象的指针。我可以做这样的事情:
struct Message {
std::map<int, int> intPayload;
std::map<int, std::string> strPayload;
short id;
};
但这不仅是丑陋和不洁,而且可能浪费空间,但这并不能解释我是否想传递一个相对奇特的数据类型,例如指向类实例的指针。我该怎么用呢?
答案 0 :(得分:2)
答案 1 :(得分:2)
您可以根据访客模式确定解决方案 作为一个最小的工作示例:
struct Listener;
struct Message {
virtual void accept(Listener &) = 0;
};
struct SimpleMessage: Message {
void accept(Listener &) override;
int i;
};
struct ComplexMessage: Message {
void accept(Listener &) override;
int i;
char c;
double d;
};
struct Listener {
void visit(SimpleMessage &) {}
void visit(ComplexMessage &) {}
void listen(Message &m) { m.accept(*this); }
};
void SimpleMessage::accept(Listener &l) { l.visit(*this); }
void ComplexMessage::accept(Listener &l) { l.visit(*this); }
struct Bus {
Bus(Listener *l): l{l} {}
void publish(Message &m) { l->listen(m); }
private:
Listener *l;
};
int main() {
Listener l;
Bus b{&l};
SimpleMessage sm;
ComplexMessage cm;
b.publish(sm);
b.publish(cm);
}
撇开Bus
的实施是微不足道的事实,请注意visit
中的Listener
成员函数可以是虚拟的。
这样,您的所有侦听器都可以从该类派生,并覆盖所需的方法
Bus
将接受一组Listener
s,无论实际派生类型是什么,还是通用Message
。另一方面,消息将自己提升为正确的派生类型,并将引用传递给给定的侦听器。
访问者模式背后的技术也称为双重调度,如果您想进一步探索它。
答案 2 :(得分:1)
有很多方法可以做到这一点。这是C ++ 17 std::variant
的一个例子:
std::vector<std::variant<int, std::string>> vec1;
vec1.emplace_back(1);
vec1.emplace_back("hello"s);
doSomethingWithInt( std::get<int>(vec1[0]) );
doSomethingWithString( std::get<std::string>(vec1[1]) );
vec1
是int
或std::string
元素的列表。
您还可以使用静态访问者:
std::vector<std::variant<int, std::string>> vec2;
// ...
for(auto&& variant : vec1) {
variant.visit([](auto value){
using t = decltype(value);
if constexpr (std::is_same_v<t, int>) {
std::cout << "value is a int!" << std::endl;
} else if constexpr (std::is_same_v<t, std::string>) {
std::cout << "value is a string!" << std::endl;
}
});
}