gpt4 book ai didi

c++ - 根据运行时值调用不同的模板函数特化

转载 作者:行者123 更新时间:2023-11-28 05:29:25 29 4
gpt4 key购买 nike

这与 previous question 有关因为它是同一个系统的一部分,但这是一个不同的问题。

我正在开发一个内部消息传递系统,该系统旨在向消费者发送消息 ( struct s)。

当项目要使用消息系统时,它会定义一组消息(enum class)、数据类型(struct)以及这些实体之间的关系:

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; };

请注意,不同类型的消息可能使用相同的数据类型。

我在上一个问题中讨论了发送这些消息的代码。有一个模板化方法可以发送任何消息,并使用上面的模板定义维护类型安全。它工作得很好。

我的问题是关于消息接收类的。有一个基类,它实现了如下方法:

ReceiveMessageTypeA(const Foo & data) { /* Some default action */ };
ReceiveMessageTypeB(const Bar & data) { /* Some default action */ };
ReceiveMessageTypeM(const Foo & data) { /* Some default action */ };

然后它实现了一个单一的消息处理函数,像这样:

bool ProcessMessage(MessageType msgType, void * data) {
switch (msgType) {
case TypeA:
ReceiveMessageTypeA(data);
break;

case TypeB:
ReceiveMessageTypeB(data);
break;

// Repeat for all supported message types

default:
// error handling
break;
}
}

当需要一个消息接收者时,这个基类被扩展,并且所需的ReceiveMessageTypeX方法得到实现。如果那个特定的接收者不关心消息类型,相应的函数就不会实现,而是使用基类的默认值。

旁注:忽略我正在传递 void * 的事实而不是具体的类型。中间还有一些代码可以处理所有这些,但这不是相关的细节。

该方法的问题在于添加了新的消息类型。以及必须定义 enum , struct , 和 expected_type<>特化,必须修改基类以添加新的 ReceiveMessageTypeX默认方法,以及 ProcessMessage 中的 switch 语句必须更新功能。

我想避免手动修改基类。具体来说,我想使用存储在 expected_type 中的信息做繁重的工作,避免重复。


这是我尝试的解决方案:

在基类中,定义一个方法:

template <MessageType msgType>
bool Receive(expected_type<msgType>::type data) {
// Default implementation. Print "Message not supported", or something
}

然后,子类可以只实现他们关心的特化:

template<> Receive<MessageType::TypeA>(const Foo & data) { /* Some processing */ }
// Don't care about TypeB
template<> Receive<MessageType::TypeM>(const Foo & data) { /* Some processing */ }

我认为这解决了部分问题;我不需要在基类中定义新方法。

但我不知道如何去掉 switch 语句。我希望能够做到这一点:

bool ProcessMessage(MessageType msgType, void * data) {
Receive<msgType>(data);
}

这当然不行,因为模板不是那样工作的。

我想到的事情:

  1. expected_type 生成 switch 语句结构。我不知道该怎么做。
  2. 维护某种函数指针映射,并调用所需的指针。问题是我不知道如何在不重复 expected_type 中的数据的情况下初始化 map 。 ,我不想这样做。
  3. 定义 expected_type使用宏,然后玩预处理器游戏将该数据也按摩到 switch 语句中。这可能是可行的,但我尽量避免使用宏。

因此,总而言之,我希望能够根据运行时值调用不同的模板特化。这对我来说似乎是矛盾的,但我希望有人能给我指出一个有用的方向。即使这告诉我这不是一个好主意。

我可以改变expected_type如果需要,只要它不破坏我的 Send方法(参见我的 other question )。

最佳答案

您对 expected_typeReceive 模板的想法是正确的;只需一步即可完成所有工作。

首先,我们需要提供一些方法来枚举 MessageType:

enum class MessageType {
_FIRST = 0,
TypeA = _FIRST,
TypeB,
TypeM = 100,
_LAST
};

然后我们可以在编译时枚举 MessageType 并生成调度函数(使用 SFINAE 跳过 expected_types 中未定义的值):

// this overload works when expected_types has a specialization for this value of E
template<MessageType E> void processMessageHelper(MessageType msgType, void * data, typename expected_type<E>::type*) {
if (msgType == E) Receive<E>(*(expected_type<E>::type*)data);
else processMessageHelper<(MessageType)((int)E + 1)>(msgType, data, nullptr);
}
template<MessageType E> void processMessageHelper(MessageType msgType, void * data, bool) {
processMessageHelper<(MessageType)((int)E + 1)>(msgType, data, nullptr);
}
template<> void processMessageHelper<MessageType::_LAST>(MessageType msgType, void * data, bool) {
std::cout << "Unexpected message type\n";
}

void ProcessMessage(MessageType msgType, void * data) {
processMessageHelper<MessageType::_FIRST>(msgType, data, nullptr);
}

关于c++ - 根据运行时值调用不同的模板函数特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39842853/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com