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

点赞
stackoverflow用户596781
stackoverflow用户596781

小节

  • 成员函数不是自由函数。这个类型完全不同,一个成员函数指针(PTMF)是一个完全不同且不兼容的对象与函数指针(例如,PTMF通常更大)。
  • 最重要的是,一个指向成员的指针必须总是与一个实例指针一起使用,以调用其成员,因此您甚至不能像使用函数指针一样使用PTMF。

与C代码交互的最简单解决方案是编写一个全局包装器函数来调度您的调用,或将您的成员函数静态化(在这种情况下,它本质上变成了自由函数):

// global!

Engine * myEngine;
int theCallback(lua_State * L)
{
  return myEngine->pcall_log(L);
}

Engine::Run()
{
  /* ... */
  myEngine = this;
  luabind::set_pcall_callback(&theCallback);
  /* ... */
}

这里的概念问题是,您有一个引擎类,尽管实际上只有一个单一实例。对于具有许多对象的真正类来说,PTMF将毫无意义,因为您必须指定用于调用的对象,而您的引擎类可能基本上是一个单例类,完全可以静态化(即一个功过了命名空间)。

2011-08-02 07:33:16
stackoverflow用户671858
stackoverflow用户671858

作为回调函数,通常使用 static function s:

class Engine //为了简洁未显示整个类
{
    ....
    static int pcall_log(lua_State*);
    ...
}

这样可以解决你的问题。

2011-08-02 07:34:14
stackoverflow用户1800813
stackoverflow用户1800813

不适用于您的 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);

但请注意。您必须注意该对象的寿命。也必须匹配调用约定。

2018-09-20 14:08:32
stackoverflow用户4743275
stackoverflow用户4743275

在 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 中也可以使用。

2020-11-20 19:26:16