有没有一种方法可以使模板匹配所有指针类型

Is there a way to make a template match all pointer types?

本文关键字:类型 指针 可以使 方法 一种 有没有      更新时间:2023-10-16

有没有一种方法可以使模板化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的函数时,我必须编写与其他pointer版本相同的GetFromStack的另一个版本。

这个系统的使用方式如下:

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作为intT_param1作为MyStruct*T_param2也作为整数。我已经有GetFromStackPushLuaTypeint版本,但我没有MyStruct*版本。按照现在的实现方式,我必须为我提出的每种类型编写一个新版本的GetFromStack,即使每个实现都是一样的。

编辑:如果有一种方法可以确定一个类型是指针还是不在编译类型,Andreas的解决方案就会奏效。如果我的T_param1是MyStruct*,那么它将按原样传递给GetFromStack,而不是MyStruct

如果我理解正确,您需要为不同的类型实现不同的函数,但所有指针类型的实现恰好相同。

如果该值是作为参数传递的,那么您将使用普通函数重载。在这种情况下,可以使用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);
}

好的,这是一个基于您的附加信息的新尝试。正如前面所说的,如果您选择使用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);

我不太确定这是否是您想要的,但是。。。

传递函数指针怎么样?

你的编译器可能会给你一堆警告,但它应该可以工作。

void *GetFromStack(void *p, int index, void * (*func)(void *, int)) {
    return func(p, index);
}

void * (*func)(void *, int)是一个函数指针,指向一个接受void指针和int并返回void指针的函数,该指针作为GetFromStack的前两个参数提供。只需使用引用运算符&来获取要调用的函数的函数指针。