有没有办法让模板化的C ++函数隐式地将所有指针转换为void*
?我正在研究一个轻量级的Lua绑定,我想避免在我需要void*
版本时为每个指针类型编写完全相同的函数。
声明:
template<class T>
T GetFromStack(lua_State* L, int index);
定义:
template<> void* GetFromStack<void*>(lua_State* L, int index)
{
return lua_touserdata(L, index);
}
如果我要调用myVariable = GetFromStack<MyStruct*>(L, 0);
,C ++编译器会抱怨我没有为MyStruct*
定义函数。是否可以隐含地将每个指针类型与void*
版本匹配?
编辑:
我看到我的问题有点混乱,我不确定如何说出来。我正试图想出一个自动绑定系统。从另一个模板化函数调用此GetFromStack
函数:
template<class T_return, class T_param1, class T_param2 >
int LuaFunction(lua_State* L, T_return (*func)(T_param1,T_param2));
实现如下:
template<class T_return, class T_param1, class T_param2 >
int LuaFunction(lua_State* L, T_return (*func)(T_param1,T_param2))
{
T_param1 a = GetFromStack<T_param1>(L, 1);
T_param2 b = GetFromStack<T_param2>(L, 2);
T_return ret = func(a,b);
PushLuaType(L, ret); // <-- This is another templated function
// like GetFromStack that has the same problem
return 1;
}
然后我用一个简单的宏创建一个我希望用Lua公开的函数的Lua版本:
#define DeclareLuaFunction(function) \
static int ##function##_lua_(lua_State* L) \
{ \
return LuaFunction(L, function); \
}
只要我使用预定义类型,这种方法就非常有效。我为所有“基本”类型(int,float等)编写了GetFromStack
版本,显然是void*
。但我不想为每个自定义类型的指针编写一个。当我创建一个使用MyStruct2
的函数时,我必须编写另一个GetFromStack
版本,该版本与其他pointer
版本相同。
这个系统会像这样使用:
struct MyStruct
{
int a;
float b;
};
int AddToMyStruct(MyStruct* s, int x)
{
int original = s->a;
s->a += x;
return original;
}
DeclareLuaFunction(AddToMyStruct);
其中T_return
为int
,T_param1
为MyStruct*
,T_param2
为整数。我已经拥有int
和GetFromStack
的{{1}}个版本,但我没有PushLuaType
个版本。按照现在实现的方式,我必须为我提出的每种类型编写一个新版本的MyStruct*
,即使每个实现都是相同的。
GetFromStack
,则会将其传递给MyStruct*
,而不是GetFromStack
。
答案 0 :(得分:3)
如果我理解正确,你需要以不同的方式为不同的类型实现该函数,但所有指针类型的实现都是相同的。
如果值作为参数传递,则使用正常的函数重载。在这种情况下,您可以使用enable_if
。
template<typename T>
typename std::enable_if<std::is_pointer<T>::value, T>::type
GetFromStack(lua_State* L, int index)
{
return lua_touserdata(L, index);
}
答案 1 :(得分:2)
好的,这是基于您的其他信息的新尝试。如前所述,如果您选择使用C ++ 11,可以更轻松地完成大部分工作,但这也适用于大多数较旧的编译器。
首先,您需要一种方法来检测您的模板参数T是否为指针,您可以使用std::is_pointer<>
(这是首选)或自己定义一个:
template <class T>
struct is_pointer
{
enum {value = false};
};
template <class T>
struct is_pointer<T *>
{
enum {value = true};
};
template <class T>
struct is_pointer<const T *>
{
enum {value = true};
};
接下来,您需要根据它改变您的实现。为此,我们引入了一个辅助类(或结构,因为我懒得编写public
),它有几个特殊化,一个用于每个普通类型,一个用于指针:
template <bool ispointer, class T>
struct GetFromStackHelper;
template <>
struct GetFromStackHelper<false, int>
{
static int GetFromStackFun(lua_State *l, int index)
{
return lua_tointeger(l, index);
}
};
// ... add the rest of the built in types here
template <class T>
struct GetFromStackHelper<true, T>
{
static T GetFromStackFun(lua_State *l, int index)
{
return static_cast<T>(lua_touserdata(l, index));
}
};
最后我们将它与GetFromStack
函数绑在一起,现在不应该有任何特化:
template <class T>
T GetFromStack(lua_State *l, int index)
{
return GetFromStackHelper<is_pointer<T>::value, T>::GetFromStackFun(l, index);
}
您可以将其用作:
int i = GetFromStack<int>(luaState, 6);
MyStruct *p = GetFromStack<MyStruct *>(luaState, 5);
答案 2 :(得分:0)
我不太确定这是否是您正在寻找的,但是......
如何传递函数指针?
你的编译器可能会给你一堆警告,但它应该可以工作。
void *GetFromStack(void *p, int index, void * (*func)(void *, int)) {
return func(p, index);
}
void * (*func)(void *, int)
是一个函数指针,它接受一个void指针和一个int并返回一个void指针,你将它作为前两个参数提供给GetFromStack。只需使用引用运算符&
来获取您希望它调用的函数的函数指针。