本文介绍了加强模板功能参数之间的期望关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在改进内部消息库,该库旨在在我们的应用程序内部向外部用户发送消息。一条消息由 MessageType 枚举类)和一些数据( struct )。每个 MessageType :: 对应一个特定的数据类型(例如, MessageType :: TypeA 将始终包含 Foo )。但是,多种消息类型可以使用相同的结构(例如, MessageType :: TypeM 也可以使用 Foo )。 / p>

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

  SendMessageTypeA(Foo data)
SendMessageTypeB(条形数据)
SendMessageTypeM(Foo数据)

如果有很多消息,这可以导致大量代码重复(方法主体在本质上是相同的,不同的参数类型除外)。



我实现了一个新方法:

  template< typename structType> 
void Send(MessageType msgType,const structType& messageData)

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



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



我不确定如何实现。我考虑过:


  1. 声明所有 SendMessageX()方法,并使用他们调用 Send< MessageX>()。这确实减少了重复,但是每次定义消息时我仍然必须创建一个新方法。

  2. 尝试使用 static_assert 捕捉不匹配。我不确定如何将 MessageType s映射到所需的 struct

  3. 我叫错了树


解决方案

如果可以将枚举值提升为

  template< MessageType E,Class Data> 
无效Send(Data const&){...}

我们可以创建一个类模板,专门针对每个枚举以及该枚举的期望:

  template< MessageType E> struct Expected_type; 
模板<> struct Expected_type< MessageType :: TypeA> {using type = Foo; };
模板<> struct Expected_type< MessageType :: TypeB> {using type = Bar; };
模板<> struct Expected_type< MessageType :: TypeM> {using type = Foo; };

模板< MessageType E>
使用Expected_type_t =类型名Expected_type< E> :: type;

然后我们可以用它来写静态断言:

 模板< MessageType E,类Data> 
void Send(Data const&){
static_assert(std :: is_same< Data,Expected_type_t< E>> {},!);
// ...
}

或者,可以使用该类模板直接设置 Data 类型:

  template< MessageType E> 
无效Send(expected_type_t< E> const&){
...
}


I'm working on improving an in-house messaging library, designed to send messages internally within our applications, and to external consumers. A message consists of a MessageType (enum class) and some data (struct). Each MessageType:: corresponds to a particular data type (e.g., MessageType::TypeA will always contain Foo). However, multiple message types could use the same struct (e.g., MessageType::TypeM could also use Foo).

We have a class that can send messages. Our previous implementation of the message sender class defines a method for each type:

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

When there are lots of messages, this can result in a lot of code duplication (the method body is essentially the same, with the exception of the different parameter types).

I've implemented a new method:

template<typename structType>
void Send(MessageType msgType, const structType & messageData)

This single method can send any message, depending on the appropriate template parameter being provided. Note that the MessageType is always known at compile time.

The problem is that this new method does not enforce the relationship between MessageType and struct. For example, Send<Foo>(MessageType::TypeB, data) will compile, even though MessageType::TypeB should contain Bar. The mismatch will be detected at runtime, but I'd like to make it a compile time error.

I'm not sure how to achieve this. I've considered:

  1. Declaring all the SendMessageX() methods, and use them to call Send<MessageX>(). This does reduce the duplication, but I still have to create a new method every time a message is defined.
  2. Attempting to use static_assert to catch the mismatch. I'm not sure how to map MessageTypes to their desired struct.
  3. I'm barking up the wrong tree
解决方案

If you can lift the enum to a compile time constant, then it's possible:

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

We can create a class template, specialized on each enum with what that enum expects:

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;

And then we can use that to just write that static assert:

template <MessageType E, class Data>
void Send(Data const& ) {
    static_assert(std::is_same<Data, expected_type_t<E>>{}, "!");
    // ...
}

Alternatively, could use that class template to set the Data type directly:

template <MessageType E>
void Send(expected_type_t<E> const& ) {
    ...
}

这篇关于加强模板功能参数之间的期望关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-14 17:54