2015-11-06 155 views
1

对于我正在尝试编写的应用程序,我需要能够在interface中写入GLEnable(GL_REPEAT)(得到这个工作)。一旦用户这样做,系统应该用正确的参数调用该函数。带参数的Void *函数

对于这一点,我使用以下变量来获得正确的功能:

std::map<std::string, void(*)(GLenum)> glEnableDisable;

并通过存储在它的数据:

glEnableDisable["glEnable"] = glEnable; 
glEnableDisable["glDisable"] = glDisable; 

(注意上面给出警告“'='不能从'void(__stdcall *)(GLenum)'转换为'void(__cdecl *)(GLenum)'”)

最后,调用函数通过:

((void (*)(GLenum)) Main.glEnableDisable[SplittedUp[0]])(Parameter); 

现在,我不知道我做错了。我有这个没有参数工作正常,但我真的需要这个参数。

由于提前,

乔伊

+0

这是从来没有真正的“工作正常”不带参数。你很幸运,你没有因为使用错误的调用约定而崩溃('__stdcall'与'__cedcl') – PaulMcKenzie

+0

__stdcall来自Visual Studio给出的警告。它不是我的代码的一部分(我试图从OpenGL调用glEnable函数) –

+0

忽略警告给自己的危险。你应该问自己(或者stackoverflow)什么是__stdcall什么是__cdecl,为什么VS会警告我甚至不在我的代码中的东西?甚至在尝试运行任何东西之前。 –

回答

2

更改此:

std::map<std::string, void(*)(GLenum)> glEnableDisable; 

这样:

std::map<std::string, std::function<void(GLenum)>> glEnableDisable; 

,再也不用担心再次调用约定。一个std::function能够存储任何函数或可调用对象,无论它的调用约定是什么。不需要

演员:

Main.glEnableDisable[SplittedUp[0]])(Parameter); 
+0

谢谢:)这使得void *函数非常容易o.o –

0

的问题是“如何店std::map<std::string, void(*)(GLenum)>接受参数的函数指针”?如果是,那么答案是:这是不可能的,因为你声明了一个具有固定函数指针签名的映射。并且代码中的签名是,存储的函数指针不接受任何参数。

如果你想存储的参数,那么你有两个选择:

  1. 访问该参数不超过栈和调用指定的函数所提供的参数,包装函数。

  2. 为您正在使用的每个函数指针签名创建一个映射。

提示:幸运的是,由于错误的调用约定,程序没有崩溃。建议将呼叫约定修改为__cdecl

+0

应该在映射中的函数都使用FunctionName(GLenum)签名(如果我没有误解你的话)。我可以使用什么地图来正确存储签名?该地图只包含2个函数,glDisable和glEnable,尽管为了整洁起见,我宁愿不使用if语句来找出它是哪一个。 –

+0

@JoeyvanGangelen:不幸的是它不可能。容器(例如std :: map)只接受指定的签名。每个参数和它的数据类型都会改变签名。如果你想使它通用,你没有别的选择选择1.另一个解决方案是一个工作线程,它读取ab命令enum和一个通用数据结构来存放每个参数。在switch/case模块中,你可以识别命令并提取参数传递给函数。我知道没有优雅的解决方案,但它会工作。 –

0

很明显:

void(*)(GLenum) 

正确的原型为GLenum功能。

此处假定调用约定为C,在Visual Studio中默认为__cdecl。但是,您要调用的实际功能使用不同的调用约定,即__stdcall

像这样的东西应该解决的问题:

typedef void (__stdcall *GLenumFunc)(int, int); // or whatever your params are 
//... 
std::map<std::string, GLenumFunc> glEnableDisable; 

至于调用约定是什么:Calling Conventions on x86 platforms