有没有办法让模板匹配所有指针类型?

时间:2012-02-25 08:28:24

标签: c++ templates lua

有没有办法让模板化的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_returnintT_param1MyStruct*T_param2为整数。我已经拥有intGetFromStack的{​​{1}}个版本,但我没有PushLuaType个版本。按照现在实现的方式,我必须为我提出的每种类型编写一个新版本的MyStruct*,即使每个实现都是相同的。

编辑:安德烈亚斯的解决方案可行,如果我可以确定一个类型是否是编译类型的指针。如果我的T_param1是GetFromStack,则会将其传递给MyStruct*,而不是GetFromStack

3 个答案:

答案 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。只需使用引用运算符&来获取您希望它调用的函数的函数指针。