STL容器用于存储多种类型的值?

时间:2017-01-15 06:31:10

标签: c++ stl containers std message-bus

我有一个Message结构,我正在使用消息总线,我想发送带有消息的数据。问题是数据的类型会有所不同;也许对于一个消息我只想发送一个int,但另一个消息我想要发送几个整数,一个字符串,甚至可能是指向一个对象的指针。我可以做这样的事情:

struct Message {
    std::map<int, int> intPayload;
    std::map<int, std::string> strPayload;
    short id;
};

但这不仅是丑陋和不洁,而且可能浪费空间,但这并不能解释我是否想传递一个相对奇特的数据类型,例如指向类实例的指针。我该怎么用呢?

3 个答案:

答案 0 :(得分:2)

使用继承和多态的一个简单示例:

N times   0 1 2 3 4 5 6 7 8 9
Frequency 2 4 4 8 4 5 2 4 2 1

任何good book都应该能够为您提供更多信息。

答案 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]) );

vec1intstd::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;
        }
    });
}