2

我正在尝试使用 __stdcall 创建函数名称和函数指针的映射。以下是我目前获取函数指针的方式:

typedef int (CALLBACK* InitializeDLL)(int,int);
InitializeDLL initializeDLL = (InitializeDLL)GetProcAddress(hInstanceLibrary, "InitializeDLL");

现在我的地图:

map<string, int *__stdcall> mapInt;
mapInt["InitializeDLL"] = initializeDLL; //throws error for "InitializeDLL cannot be assigned to entity of type int*"

该错误正是我所期望的,但我需要在 __stdcall 前面添加一个明显的类型。如果我删除前面的“int”,那么它会抱怨:

Error: expected a type specifier

如果我仅在前面包含“int”的地图对象创建后尝试编译它,则会引发错误:

error C2059: syntax error : '>'

这对我来说没有多大意义。那么使用 __stdcall 作为地图类型的正确方法是什么?在它前面添加 int 对我来说似乎很可疑,但如果我不添加它,它就会抱怨它需要指定类型。

此外,如果这令人困惑,CALLBACK 是 __stdcall 的#define。

4

2 回答 2

4

您使用__stdcall的是一种类型,但它不是一种类型。您需要在地图定义中使用您的函数指针类型。

map<string, InitializeDLL> mapInt;

我不确定您为什么首先尝试做其他事情,因为您已经在其他地方使用过这种类型,难道不是很明显这里也需要它吗?

于 2012-06-20T16:53:32.517 回答
3

函数指针类型不限于单个函数。例如,您的InitializeDLL函数指针类型可以保存指向具有此签名的任何函数的指针:int foo(int,int).

也许CallbackFunction该 typedef 是一个更好的名称,因为它包含所有具有可用于回调的签名的函数:

typedef int (CALLBACK* CallbackFunction)(int,int);
CallbackFunction initializeDLL =
    (InitializeDLL)GetProcAddress(hInstanceLibrary, "InitializeDLL");
map<string, CallbackFunction> mapInt;
mapInt["InitializeDLL"] = initializeDLL;

有更通用的方法来处理函数(甚至是成员函数)。如果你有能力/愿意使用新的 C++11 特性,你可以使用std::functionand std::bind. 如果没有,那么您可以使用boost::functionboost::bind。这些工具的 Boost 和 C++11 版本的使用方式完全相同。Boost 文档将比 cppreference 更有帮助。

如果您向我们展示您打算如何调用地图中的回调函数(包括函数签名不同的情况),我也许可以向您展示有关如何使用functionbind用于您的用例的示例。


您可能会考虑让所有命令回调具有相同的函数签名,然后让每个回调负责提取完成工作所需的任何参数。包含命令参数的对象可以作为参数传递给回调函数。

std::vector<boost::any>您还可以考虑以或的形式将参数列表传递给回调函数std::vector<boost::variant>。然后,回调函数将每个boost::any或转换boost::variant为与该特定参数关联的特定类型。如果命令参数类型是简单的内置类型,您甚至可以使用std:vector<UnionOfPossibleParameterTypes>,其中UnionOfPossibleParameterTypes是普通的旧 C 样式union

于 2012-06-20T17:12:46.867 回答