1

我在使用模板参数创建静态包装函数时遇到了一些麻烦。我不想将函数直接传递给包装函数,因为它需要特定的签名int (lua_State *),以便可以将其传递给以下函数:

lua_pushcfunction(L, function);

(没错,我要的是自动生成的 lua 包装器。)

我的第一个想法是创建一个带有函数指针作为非类型模板参数的模板函数。

template <void(* f)(void)>
int luaCaller(lua_State * _luaState)
{
    f();

    return 0;
}

到目前为止,这看起来相当不错。该函数具有正确的签名,并调用我通过模板参数传入的函数。

&(luaCaller<myFunc>)

当我尝试将其包装在另一个函数中时,我的问题就出现了。非类型模板参数必须外部链接,因此以下失败:

void pushFunction(lua_State * _luaState, void(* _f)(void))
{
    lua_pushcfunction(_luaState, &(luaCaller<_f>));
}

这是有道理的,因为函数的地址需要在编译时知道。您不能只输入任何指针并期望编译器知道要创建哪些类。不幸的是,如果我添加一个在编译时已知的函数指针,它仍然会失败。函数指针的值被复制到 _a 中,因此 _a 在编译时在技术上仍然未知。因此,我希望以下工作:

void pushFunction(lua_State * _luaState, void(* const _f)(void))
{
    lua_pushcfunction(_luaState, &(luaCaller<_f>));
}

或者可能

void pushFunction(lua_State * _luaState, void(* & _f)(void))
{
    lua_pushcfunction(_luaState, &(luaCaller<_f>));
}

在第一种情况下,因为不允许更改值,所以我们知道如果它是外部链接的,它在技术上仍然是外部链接的。在第二种情况下,它作为参考传递,这意味着它应该具有相同的链接,不是吗?但这些尝试都没有奏效。为什么?是否有可能以某种方式规避这一点?如何干净地自动生成调用另一个函数的函数?

4

2 回答 2

1

const限定符意味着您不允许更改某些内容,而不是说它是编译时常量。的初始值_a是在调用函数时在运行时确定的,对于 a * const &a,如果引用基础的对象不是 ,则该值甚至可以在运行时通过某些外部方式(例如另一个线程)改变const

为了使完全模板化的包装器工作,您需要为编译器提供足够的信息来为每个可能的模板参数编译一个函数,并提供在这些函数之间切换的逻辑。模板系统生成并组织相关功能,但它不是动态调度器。

如果您可以将函数指针添加到lua_State对象并消除模板参数,那将是一种解决方案。

如果将函数指针作为模板参数,您的解决方案将起作用doCaller,但这会破坏其目的。

于 2013-05-18T01:47:42.030 回答
1

与其使用非类型函数模板方法来绑定要在包装函数内部调用的辅助函数,不如将 astruct与静态luaCaller方法一起使用。这应该允许您维护传递luaCallerlua_pushcfunction.

因此,例如,您可以有一个类似于以下内容的结构:

template<void (*f) void>
struct wrapper
{   
    static int luaCaller(lua_State * _luaState)
    {
        f();

        return 0;
    }
};

template<typename Functor>
void doCaller(lua_State * _luaState, Functor wrapper)
{
    Functor::luaCaller(_luaState);
}

然后像这样称呼它:

doCaller(&luaState, wrapper<my_func>());
于 2013-05-18T02:08:40.193 回答