C++类成员函数指针指向函数指针
我使用 luabind 作为我的 lua 到 C++ 包装器。 Luabind提供了一种使用我自己的回调函数来处理lua抛出的异常的方法,set_pcall_callback()。因此,我解释了文档中的一个示例,更改是 logger->log() 函数,并将该函数放入名为“Engine”的类中,因此它不再是常规的全局函数,而是现在的成员函数,这就是我的问题所在。
以下是相关代码片段:
class Engine //Whole class not shown for brevity
{
public:
Engine();
~Engine();
void Run();
int pcall_log(lua_State*);
private:
ILogger *logger;
};
Engine::Run()
{
lua_State* L = lua_open();
luaL_openlibs(L);
open(L);
luabind::set_pcall_callback(&Engine::pcall_log); //<--- Problem line
//etc...rest of the code not shown for brevity
}
int Engine::pcall_log(lua_State *L)
{
lua_Debug d;
lua_getstack( L,1,&d);
lua_getinfo( L, "Sln", &d);
lua_pop(L, 1);
stringstream ss;
ss.clear();
ss.str("");
ss << d.short_src;
ss << ": ";
ss << d.currentline;
ss << ": ";
if ( d.name != 0)
{
ss << d.namewhat;
ss << " ";
ss << d.name;
ss << ") ";
}
ss << lua_tostring(L, -1);
logger->log(ss.str().c_str(),ELL_ERROR);
return 1;
}
这是编译器在编译期间所说的内容:
C:\pb\engine.cpp|31|error: cannot convert 'int (Engine::*)(lua_State*)' to 'int (*)(lua_State*)' for argument '1' to 'void luabind::set_pcall_callback(int (*)(lua_State*))'|
因此,似乎错误在于该函数需要常规函数指针,而不是类成员函数指针。有没有办法强制转换或使用中间函数指针传递给 set_pcall_callback() 函数?
谢谢你!
I am using luabind as my lua to C++ wrapper. Luabind offers a method to use my own callback function to handle exceptions thrown by lua, set_pcall_callback(). So I paraphrased an example from the documentation, the changes being the logger->log() function and putting the function in a class called 'Engine', so instead of it being a regular global function it is now a member function, which is where my problem seems to be.
Here are the relevant code snips:
class Engine //Whole class not shown for brevity
{
public:
Engine();
~Engine();
void Run();
int pcall_log(lua_State*);
private:
ILogger *logger;
};
Engine::Run()
{
lua_State* L = lua_open();
luaL_openlibs(L);
open(L);
luabind::set_pcall_callback(&Engine::pcall_log); //<--- Problem line
//etc...rest of the code not shown for brevity
}
int Engine::pcall_log(lua_State *L)
{
lua_Debug d;
lua_getstack( L,1,&d);
lua_getinfo( L, "Sln", &d);
lua_pop(L, 1);
stringstream ss;
ss.clear();
ss.str("");
ss << d.short_src;
ss << ": ";
ss << d.currentline;
ss << ": ";
if ( d.name != 0)
{
ss << d.namewhat;
ss << " ";
ss << d.name;
ss << ") ";
}
ss << lua_tostring(L, -1);
logger->log(ss.str().c_str(),ELL_ERROR);
return 1;
}
Here is what the compiler says during compilation:
C:\pb\engine.cpp|31|error: cannot convert 'int (Engine::*)(lua_State*)' to 'int (*)(lua_State*)' for argument '1' to 'void luabind::set_pcall_callback(int (*)(lua_State*))'|
So it seems that the error is that the function expects a regular function pointer, not a class member function pointer. Is there a way to cast or use an intermediate function pointer to pass to the set_pcall_callback() function?
Thank you!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不。成员函数不是自由函数。类型完全不同,并且指向成员函数的指针 (PTMF) 是与函数指针完全不同且不兼容的对象。 (例如,PTMF 通常要大得多。)最重要的是,指向成员的指针必须始终与指向要调用其成员的对象的实例指针一起使用,因此您甚至不能使用 PTMF 与使用函数指针的方式相同。
与 C 代码交互的最简单的解决方案是编写一个全局包装函数来分派您的调用,或者使您的成员函数静态(在这种情况下,它本质上变成一个自由函数):
这里的概念问题是你有一个引擎类,尽管你实际上只有一个它的实例。对于具有许多对象的真正类,PTMF 没有意义,因为您必须指定要用于调用的对象,而您的引擎类可能本质上是一个可以完全静态的单例类(即美化的命名空间) )。
No. A member function is not a free function. The type is entirely different, and a pointer to a member function (PTMF) is a completely different, incompatible object from a function pointer. (A PTMF is usually much bigger, for example.) Most importantly a pointer-to-member must always be used together with an instance pointer to the object whose member you want to call, so you cannot even use a PTMF the same way you use a function pointer.
The easiest solution for interacting with C code is to write a global wrapper function that dispatches your call, or to make your member function static (in which case it becomes essentially a free function):
The conceptual problem here is that you have an engine class, although you will practically only have one single instance of it. For a genuine class with many objects, a PTMF wouldn't make sense because you'd have to specify which object to use for the call, whereas your engine class perhaps is essentially a singleton class which could be entirely static (i.e. a glorified namespace).
不适合您的 LUA 问题,但可能适用于其他库:
如果一个函数请求像 func(void* param, ...) 这样的函数指针,并且您可以确保对象的生命周期大于存储的函数指针,那么从技术上讲您也可以使用方法指针(在堆栈),但 C++ 禁止将方法指针直接转换为函数指针。
但通过一个小技巧,您还可以将方法指针转换为函数指针:
使用它,您可以将方法指针与 libmicrohttpd 一起使用:
但请注意这一点。您必须关心该对象的生命周期。调用约定也必须匹配。
Not suitable for your LUA problem, but maybe on other libraries:
If a function requests a a function pointer like func(void* param, ...) and you can ensure that the lifetime of your object is greater than the stored function pointer, then you could technically also use a method pointer (looks the same on the stack), but C++ prevents direct casting of method pointers to function pointers.
But with a little trick, you can also cast method pointers to function pointers:
Using that, you can use method pointers for example with libmicrohttpd:
But be aware of it. You must take care of the lifetime of that object. Also the calling conventions must match.
作为回调,通常使用静态函数:
这可以解决您的问题。
As a callback, it is usual to use
static function
s:This would solve your issue.
从方法指针到函数指针的显式转换在 C++ 中是非法的 - 期间。
但有一个黑客。我们必须首先将 (const) 方法指针转换为 (const) void*,然后转换为 (const) 函数指针。它有效。为什么不呢?所有东西,我的意思是所有东西都可以由
void*
指向,因为所有东西都有一个地址。警告:以下是 DAAEINGEROUS 黑客领域。如果您正在为战斗机或其他类似设备开发软件,您应该更了解如何使用它。我不负责!我在这里提供这个只是出于教育目的。
诀窍是我们必须通过中间转换在方法指针和函数指针之间进行转换,转换为可能的 cv(const-volatile)限定的
void*
。这样我们就可以通过函数指针来调用成员函数(指针),第一个参数是指向目标类对象的
Type*
指针,相当于成员函数调用的>这个*。
给定一个:
MethodPointerType f;
然后
或者为了使其更明确,对于非常量和常量成员函数,按顺序使用以下两个:
在这里使用 C++17 中的完整可编译示例来使用它: https://onlinegdb.com/HybR8crqw
它也适用于 Visual Studio。
Explicit conversion from method pointer to function pointer is illegal in C++ - period.
But there is a hack. We have to first convert the (const) method pointer to (const) void* and then to (const) function pointer. And it works. And why wouldn't it? Everything and I mean everything can be pointed to by a
void*
because everything has an address.WARNING: The below is DAAEINGEROUS hack territory. If you're developing software for a fighter jet or whatnot, you should know better than to use this. I'm not responsible! I'm just providing this here for educational purposes.
The trick is we must convert between method pointer and function pointer through an intermediate conversion to, potentially cv (const-volatile) qualified,
void*
.This way we are able to call a member function (pointer) through a function pointer, with the first argument being a
Type*
pointer to the target class object, which is equivalent to the member function call'sthis*
.Given a:
MethodPointerType f;
then
or to make it more explicit use two of the following in sequence, for non-const and const member functions:
Play with it live here with a complete compilable sample in C++17: https://onlinegdb.com/HybR8crqw
It works in Visual Studio too.