C++类成员函数指针转换为函数指针
我正在使用luabind作为我的lua到C ++包装器。 Luabind提供了一种方法,可以使用自己的回调函数来处理lua抛出的异常,set_pcall_callback()。因此,我对文档中的一个示例进行了释义,更改了logger-> log()函数,并将函数放在名为“Engine”的类中,因此它不再是常规全局函数,而是成员函数,这就是我的问题所在。
以下是相关的代码片段:
`` ` class Engine //没有显示整个class以简洁为目的 { public: 引擎(); ~ Engine(); void Run(); int pcall_log(lua_State *); 私人: ILogger * logger; };
Engine :: Run() { lua_State * L = lua_open(); luaL_openlibs(L); 打开(L); luabind :: set_pcall_callback(&Engine :: pcall_log);<---问题行 // etc ...不显示代码以简洁为目的 }
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); 返回1; }
`` `
这是编译过程中编译器所说的:
`` ` C:\ pb \ engine.cpp | 31 |错误:无法将“int(Engine :: *)(lua_State )”转换为“int()(lua_State )”的参数1,以便“void luabind :: set_pcall_callback(int()(lua_State *))”|
`` `
因此,错误在于该函数期望普通函数指针,而不是类成员函数指针。是否有一种方法可以将或使用中间函数指针来传递给set_pcall_callback()函数?
谢谢!
原文链接 https://stackoverflow.com/questions/6908591
作为回调函数,通常使用 static function
s:
class Engine //为了简洁未显示整个类
{
....
static int pcall_log(lua_State*);
...
}
这样可以解决你的问题。
不适用于您的 LUA 问题,但可能适用于其他库:
如果一个函数请求一个函数指针,如 func(void* param, ...)
,您可以确保您的对象的生存期比存储的函数指针更长,那么您也可以在技术上使用方法指针(在堆栈上看起来相同),但 C++ 阻止将方法指针直接转换成函数指针。
但是,通过一点技巧,您也可以将方法指针转换为函数指针:
template<typename M> inline void* GetMethodPointer(M ptr)
{
return *reinterpret_cast<void**>(&ptr);
}
使用这个方法,您可以在使用 libmicrohttpd
的示例中使用方法指针:
this->m_pDaemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, this->m_wPort, NULL, NULL, reinterpret_cast<MHD_AccessHandlerCallback>(GetMethodPointer(&CMyWebServer::AccessHandlerCallback)), this, MHD_OPTION_END);
但请注意。您必须注意该对象的寿命。也必须匹配调用约定。
在 C++ 中,将方法指针显式转换为函数指针是非法的——没有例外。
但是,有一个 hack。我们必须先将 (const) 方法指针转换为 (const) void,然后再将其转换为 (const) 函数指针。这样就可行了。为什么不行呢?因为每个东西——我是指每个东西——都可以被 void 指向,因为每个东西都有一个地址。
警告:以下是危险的 hack 领地。如果你正在开发战斗机或其他类似软件,你应该知道不能使用这个。我不负责! 我只是提供这个给教育目的。
技巧在于,我们必须通过中间转换将方法指针转换为函数指针,可能是 cv(const-volatile)限定的 void*。
这样,我们就能够通过函数指针调用成员函数(指针),其中第一个参数是指向目标类对象的 Type* 指针,这相当于成员函数调用中的 this*。
给定:
MethodPointerType f;
那么
FunctionPointerType m_pFn = reinterpret_cast<FunctionPointerType>(reinterpret_cast<void*&>(f));
或者对于非 const 和 const 成员函数,使用以下两个模板:
template<typename MP>
void* getMethodVoidPointer(MP ptr)
{
return *reinterpret_cast<void**>(&ptr);
}
template<typename FP>
FP getFunctionPointer(void* p)
{
return reinterpret_cast<FP>(p);
}
template<typename MP>
const void* getMethodConstVoidPointer(MP ptr)
{
return *reinterpret_cast<const void**>(&ptr);
}
template<typename FP>
FP getConstFunctionPointer(const void* p)
{
return reinterpret_cast<FP>(p);
}
在 C++17 中,这里提供了一个完整的编译示例:https://onlinegdb.com/HybR8crqw。
在 Visual Studio 中也可以使用。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
小节
与C代码交互的最简单解决方案是编写一个全局包装器函数来调度您的调用,或将您的成员函数静态化(在这种情况下,它本质上变成了自由函数):
// global! Engine * myEngine; int theCallback(lua_State * L) { return myEngine->pcall_log(L); } Engine::Run() { /* ... */ myEngine = this; luabind::set_pcall_callback(&theCallback); /* ... */ }
这里的概念问题是,您有一个引擎类,尽管实际上只有一个单一实例。对于具有许多对象的真正类来说,PTMF将毫无意义,因为您必须指定用于调用的对象,而您的引擎类可能基本上是一个单例类,完全可以静态化(即一个功过了命名空间)。