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

STL Container for storing multiple types of values?

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

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

但这不仅丑陋而且不干净,而且可能会造成浪费 space,但如果我想传递一个相对奇特的数据类型,例如指向 class 例如。我应该为此使用什么?

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

struct MessageBase
{
    // The function to send *this* message to the receiver
    virtual void send(ReceiverClass*) = 0;
};

struct MessageInt : MessageBase
{
    int payload;

    void send(ReceiverClass* receiver)
    {
        // Code to send this message type to the receiver...
    }
};

struct MessageString : MessageBase
{
    std::string payload;

    void send(ReceiverClass* receiver)
    {
        // Code to send this message type to the receiver...
    }
};

// ...

// Vector to store the messages
std::vector<MessageBase*> messages;

// Add a couple of messages
messages.push_back(new MessageInt{123});
messages.push_back(new MessageString{"Foobar"});

// Send the message to some receiver
for (auto const* message : messages)
    message->send(some_reciver_object);

任何good book应该可以给你更多的信息。

您可以将您的解决方案基于访客模式。
作为一个最小的工作示例:

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 的实现很简单这一事实,请注意 Listener 中的 visit 成员函数可以是虚拟的。
这样,您的所有侦听器都可以从 class 派生并覆盖所需的方法。
Bus 将接受一组 Listener,无论实际的派生类型是什么,以及一个泛型 Message。另一方面,message 会将自身提升为正确的派生类型,并将引用传递给给定的侦听器。

访问者模式背后的技术也称为双重调度,如果您想进一步探索它。

有很多方法可以做到这一点。这是一个 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;
        }
    });
}