C++ 强制实现模板函数参数之间的所需关系
我正在努力改进一个内部消息传递库,该库设计用于在我们的应用程序内部以及向外部消费者发送消息。消息由C++ 强制实现模板函数参数之间的所需关系,c++,templates,c++11,C++,Templates,C++11,我正在努力改进一个内部消息传递库,该库设计用于在我们的应用程序内部以及向外部消费者发送消息。消息由MessageType(enum class)和一些数据(struct)组成。每个MessageType::对应于特定的数据类型(例如,MessageType::TypeA将始终包含Foo)。但是,多个消息类型可以使用同一个结构(例如,MessageType::TypeM也可以使用Foo) 我们有一个可以发送消息的类。我们以前的message sender类实现为每种类型定义了一个方法: SendM
MessageType
(enum class
)和一些数据(struct
)组成。每个MessageType::
对应于特定的数据类型(例如,MessageType::TypeA
将始终包含Foo
)。但是,多个消息类型可以使用同一个结构(例如,MessageType::TypeM
也可以使用Foo
)
我们有一个可以发送消息的类。我们以前的message sender类实现为每种类型定义了一个方法:
SendMessageTypeA(Foo data)
SendMessageTypeB(Bar data)
SendMessageTypeM(Foo data)
当存在大量消息时,这可能会导致大量代码重复(方法体基本相同,不同的参数类型除外)
我实现了一种新方法:
template<typename structType>
void Send(MessageType msgType, const structType & messageData)
模板
void Send(MessageType msgType、const structType和messageData)
此单一方法可以发送任何消息,具体取决于所提供的适当模板参数。请注意,MessageType
在编译时总是已知的
问题在于,这种新方法没有强制执行MessageType
和struct
之间的关系。例如,Send(MessageType::TypeB,data)
将被编译,即使MessageType::TypeB
应该包含Bar
。不匹配将在运行时检测到,但我想将其设置为编译时错误
我不知道如何才能做到这一点。我考虑过:
SendMessageX()
方法,并使用它们调用Send()
。这确实减少了重复,但我仍然必须在每次定义消息时创建一个新方法static\u assert
捕获不匹配。我不知道如何将MessageType
s映射到所需的struct
如果可以将枚举提升到编译时常量,则可以:
template <MessageType E, class Data>
void Send(Data const& ) { ... }
这里是另一个版本,我认为它更清晰,可以匹配消息和数据之间的多种类型
template<typename MT, typename DT>
struct CompitableCheck;
// only declare type pairs you want. A simple macro wrapping it is better
template<>
struct CompitableCheck<MsgTypeA, Bar> { static const bool value = true; };
template<>
struct CompitableCheck<MsgTypeA, Foo> { static const bool value = true; };
template<> // allow one-to-many map, TypeA -> Foo && TypeA -> Bar.
struct CompitableCheck<MsgTypeA, Bar> { static const bool value = true; };
// here goes the final function
template<typename MT, typename DT,
typename = typename std::enable_if<CompitableCheck<MT, DT>::value>>::type
void Send(MT msgType, const DT & messageData) { /* send it */ }
模板
结构完整性检查;
//仅声明所需的类型对。一个简单的宏包装它更好
模板
结构CompitableCheck{static const bool value=true;};
模板
结构CompitableCheck{static const bool value=true;};
模板//允许一对多映射,TypeA->Foo&&TypeA->Bar。
结构CompitableCheck{static const bool value=true;};
//这是最后一个函数
模板::类型
void Send(MT msgType、const DT和messageData){/*发送它*/}
您知道编译时的消息枚举吗?是的,关联在编译时是已知的,而不是您调用的Send()
值。是的,我知道编译时发送的每个消息的类型我的意思是。。。您是否总是可以调用Send(data)
?请原谅我的无知,但是“将枚举提升到编译时常量”是什么意思?这意味着可以在运行时定义枚举。如何工作?@Michael枚举值可以在运行时确定。不过,我们在编译时需要它。您应该将最后一个代码段上的省略号转换为注释,以保持与前一个代码段的一致性。这种方法工作得很好,因为预期类型在其他情况下可用于确定数据类型。
template <MessageType E, class Data>
void Send(Data const& ) {
static_assert(std::is_same<Data, expected_type_t<E>>{}, "!");
// ...
}
template <MessageType E>
void Send(expected_type_t<E> const& ) {
...
}
template<typename MT, typename DT>
struct CompitableCheck;
// only declare type pairs you want. A simple macro wrapping it is better
template<>
struct CompitableCheck<MsgTypeA, Bar> { static const bool value = true; };
template<>
struct CompitableCheck<MsgTypeA, Foo> { static const bool value = true; };
template<> // allow one-to-many map, TypeA -> Foo && TypeA -> Bar.
struct CompitableCheck<MsgTypeA, Bar> { static const bool value = true; };
// here goes the final function
template<typename MT, typename DT,
typename = typename std::enable_if<CompitableCheck<MT, DT>::value>>::type
void Send(MT msgType, const DT & messageData) { /* send it */ }