如何拆除这种开关箱

How to remove this kind of switch case?

本文关键字:开关箱 何拆      更新时间:2023-10-16

我想通用化大量内存,这些内存可能是从二进制文件加载的,并且消息id是已知的,我需要为每个内存块创建新的实例。最好的方法是什么?

目前的情况是,我需要将每个新添加的消息类型添加到以下交换机案例中。

struct Message1;
struct Message2;
void UnSerialize(int messageId, void* data) {
    switch (messageId) {
    case MESSAGE1:
        Message1* m1 = new Message1;
        std::memcpy(m1, data, sizeof(Message1));
        m1.dump();
        delete m1;
        break;
    case MESSAGE2:
        Message2* m2 = new Message2;
        std::memcpy(m2, data, sizeof(MESSAGE2));
        m2.dump();
        delete m2;
        break;
    default:
        std::cout << "Unknown Message Type.";
        break;
    }
}

我能用C++写下面这样的东西吗?没有C++11和boost可能吗?

MessageTypeList tl;
tl.append(Message1);
tl.append(Message2);
void UnSerialize(MessageTypeList tl, int messageId, void* data) {
{
    foreach( type t : tl ) {
        if (t::id == MessageId) {
            t instance = new t;
            memcpy(t, data, sizeof(t));
            instance.dump();
            delete instance;
        }
    }
}

我不确定您想做什么,但如果您只想从Message1Message2结构调用Dump函数,可以执行以下操作:

struct BaseMessge
{
    virtual void Dump() = 0;
};
struct Message1 : public BaseMessage
{
    void Dump()
    {
        //Your code
    }
};
struct Message2 : public BaseMessage
{
    void Dump()
    {
        //Your code
    }
};
void UnSerialize(BaseMessage *Message)
{
    Message->Dump();
}

有一些方法可以表达对(type,id)的列表,并为每个类型或id实现您想要的任何行为。然而,我认为开关仍然是一个非常好的方法-在任何方法中,您都必须尽快列出所有类型-但让每个案例中的代码成为一个模板函数。

template <class T>
void UnSerialize(void* data) {
    static_assert(std::is_trivially_copyable<T>::value,
                  "Message class is not trivally copyable");
    T message;
    memcpy(&message, data, sizeof(T));
    message.dump();
}
void UnSerialize(int messageId, void* data) {
    switch (messageId) {
    case MESSAGE1:
        UnSerialize<Message1>(data);
        break;
    case MESSAGE2:
        UnSerialize<Message2>(data);
        break;
    default:
        std::cout << "Unknown Message Type.";
        break;
    }
}

注意,我已经为每个案例中的代码建议了一个不同的实现:

  • 没有动态分配,消息是在函数的本地变量中分配的
  • 添加了一个静态断言,即memcpy将按预期工作

另一种完全避免switch的方法是使用虚拟方法构建一个ID和助手类实例对的数组。每个实例都来自一个派生的模板类,该类使用本例中的代码来实现该虚拟方法。然后,您只需要静态地构建该数组(我建议使用std::unique_ptr来保存指向helper类的指针)。

请注意,编写该数组与编写switch非常相似,只会使代码更难阅读。