问题描述
我正在改进内部消息库,该库旨在在我们的应用程序内部向外部用户发送消息。一条消息由 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
。不匹配会在运行时检测到,但是我想使其成为编译时错误。
我不确定如何实现。我考虑过:
- 声明所有
SendMessageX()
方法,并使用他们调用Send< MessageX>()
。这确实减少了重复,但是每次定义消息时我仍然必须创建一个新方法。 - 尝试使用
static_assert
捕捉不匹配。我不确定如何将MessageType
s映射到所需的struct
。 - 我叫错了树
如果可以将枚举值提升为
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:
- Declaring all the
SendMessageX()
methods, and use them to callSend<MessageX>()
. This does reduce the duplication, but I still have to create a new method every time a message is defined. - Attempting to use
static_assert
to catch the mismatch. I'm not sure how to mapMessageType
s to their desiredstruct
. - 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& ) {
...
}
这篇关于加强模板功能参数之间的期望关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!