我正在努力改进内部消息传递库,该库旨在在我们的应用程序内部向外部消费者发送消息。一条消息由MessageType(enum class)和一些数据(struct)组成。每个MessageType::对应于特定的数据类型(例如MessageType::TypeA将始终包含Foo)。但是,多种消息类型可以使用相同的结构(例如MessageType::TypeM也可以使用Foo)。

我们有一个可以发送消息的类。我们先前对消息发送者类的实现为每种类型定义了一个方法:

SendMessageTypeA(Foo data)
SendMessageTypeB(Bar data)
SendMessageTypeM(Foo data)

当有很多消息时,这可能导致很多代码重复(方法主体本质上是相同的,不同的参数类型除外)。

我实现了一种新方法:
template<typename structType>
void Send(MessageType msgType, const structType & messageData)

根据提供的适当模板参数,此单一方法可以发送任何消息。注意,MessageType在编译时始终是已知的。

问题在于,此新方法不会强制MessageTypestruct之间的关系。例如,即使Send<Foo>(MessageType::TypeB, data)应该包含MessageType::TypeBBar也会编译。不匹配将在运行时检测到,但是我想使其成为编译时错误。

我不确定如何实现这一目标。我考虑过:
  • 声明所有SendMessageX()方法,并使用它们调用Send<MessageX>()。这确实减少了重复,但是每次定义一条消息时,我仍然必须创建一个新方法。
  • 尝试使用static_assert捕获不匹配。我不确定如何将MessageType映射到所需的struct
  • 我吠错了树
  • 最佳答案

    如果可以将枚举值提升为编译时间常数,则可能:

    template <MessageType E, class Data>
    void Send(Data const& ) { ... }
    

    我们可以创建一个类模板,专门针对每个枚举,并提供枚举期望的内容:
    template <MessageType E> struct expected_type;
    template <> struct expected_type<MessageType::TypeA> { using type = Foo; };
    template <> struct expected_type<MessageType::TypeB> { using type = Bar; };
    template <> struct expected_type<MessageType::TypeM> { using type = Foo; };
    
    template <MessageType E>
    using expected_type_t = typename expected_type<E>::type;
    

    然后,我们可以使用它来编写静态断言:
    template <MessageType E, class Data>
    void Send(Data const& ) {
        static_assert(std::is_same<Data, expected_type_t<E>>{}, "!");
        // ...
    }
    

    或者,可以使用该类模板直接设置Data类型:
    template <MessageType E>
    void Send(expected_type_t<E> const& ) {
        ...
    }
    

    10-08 15:25