具有不同参数类型和存储类型的回调
Posted
技术标签:
【中文标题】具有不同参数类型和存储类型的回调【英文标题】:Callbacks with different parameter types and storing the type 【发布时间】:2015-10-22 21:31:45 【问题描述】:我有一个通信库,它应该根据接收到的命令类型调用回调(或处理程序)。我将处理程序存储在std::map
中(命令作为键,处理程序作为值)。
这些处理程序需要有不同的参数类型。处理程序参数始终只有一个,该参数继承自BaseType
。所以我有以下类型定义和处理程序:
class Comm
typedef std::function<void(BaseType*)> Handler;
typedef std::map<Command, Handler> Handlers;
void HandleHandshake(IntType*); // IntType inherits from BaseType
;
不幸的是,我无法将处理程序 HandleHandshake
存储在 Handlers
类型中。我只能存储具有BaseType*
类型参数的处理程序。我不能使用std::function<void()>
绑定不同的参数,因为我需要访问它的argument_type
(否则在调用处理程序时我将无法传递正确的数据类型。)。
有什么方法可以实现我想要实现的目标吗? (存储不同参数类型的处理程序,并存储类型以供进一步使用。)
显示调用处理程序的示例:
// I parsed a command. Handler of this command should take IntType as a parameter.
m_Handlers[cmd](IntType(some_data));
// But, I don't really know that it is IntType, I only have my map of handlers.
// I want something like this:
m_Handlers[cmd](m_Handlers[cmd]::argument_type(some_data));
【问题讨论】:
如果我错了,请纠正我。 1. 当您被命令调用特定命令时,您会收到some_data
和cmd
。 2. some_data
可以是不同的类型(例如 int、float)。 3. 要将其传递给您的“调用命令”方法,您需要使用模板。
顺便说一句。您可以随时使用非常不安全的evilvoid*
和static_cast
some_data
,而无需添加一层包装器。附言在我说没有更好的方法之前不要这样做。
系统需要支持多少种不同的参数类型? 5? 10? 100?未知号码(即可以由图书馆的用户扩展)?
系统需要支持多少种不同的消息?
根本问题是您的处理程序映射包含 X 处理程序。您将它们向上转换以适合 function<void(Basetype*)>
签名,这会删除您需要在正确参数中传递的信息。将正确的类型和您的论点联系在一起的唯一方法是您暗示它们匹配。要解决这个问题,要么创建一个 lambda,将 dynamic_casts 转换为正确的类型并继续传递,然后将 static_cast 传递给传递,或者不键入 erase 以开始(并在模板存储中匹配它们)。
【参考方案1】:
您始终可以存储一个执行static_cast
的 lambda。例如:
template <typename T=BaseType, typename F>
void store(Command c, F function)
Handlers[c] = [function](BaseType* obj)
function(static_cast<T*>(obj));
);
【讨论】:
我不认为可以根据需要使用它。我需要在调用处理程序时知道类型,以便为它创建它。 @TomášOndruš 所以你能做什么? 调用意味着请求。阅读它调用处理程序。 @TomášOndruš 我还是不明白你想要什么。你能在问题中添加一些例子来澄清吗? 添加了调用处理程序的示例。【参考方案2】:我以前做过类似的事情。这就是我会做的:
typedef std::function<void(BaseType*)> Handler;
typedef std::map<Command, Handler> Handlers;
然后我会让每个处理程序获取一个指向 BaseType* 的指针,以便我可以将它存储在我的地图中。
void MyIntHandler(BaseType* b)
// we know what kind of information should be passed into this method
// so we can just cast to the correct type
auto data = static_cast<IntType*>(b);
// do something with data
void MyStringHandler(BaseType* b)
auto data = static_cast<StringType*>(b);
// ...
您不能像在 C# 中那样存储类型对象,然后使用它来创建该类型的对象。您可以使用typeinfo 在运行时获取有关特定类型的一些信息。
【讨论】:
所以我不可能有确切类型的 typedef 吗?让我们说一下我的 std::function 的一些包装器。 @TomášOndruš 他是对的,他是错的。如果您知道如何使用 C++,它是一种非常强大的语言。尽管类型不是 C++ 中的对象并且您无法存储它,但您可以通过巧妙地使用模板来实现非常相似的行为。以上是关于具有不同参数类型和存储类型的回调的主要内容,如果未能解决你的问题,请参考以下文章