How to use variadic templates to make a generic Lua function wrapper?

我怕爱的太早我们不能终老 提交于 2019-11-30 07:35:32

The trick is to exploit template argument deduction by partially specializing a class template that contains the wrapper function:

// Lua API dummies ...

struct lua_State {};

template<class T> void luaU_push(lua_State*,T);
template<class T> T* luaW_check(lua_State*,int);
template<class T> T luaU_check(lua_State*,int);


// metaprogramming for creating indices ...

template<int...Ints>
struct int_pack {};

template<int Begin, int Count, int...Tail>
struct make_int_range_type {
    typedef typename make_int_range_type<Begin,Count-1,Begin+Count-1,Tail...>::type type;
};

template<int Begin, int...Tail>
struct make_int_range_type<Begin,0,Tail...> {
    typedef int_pack<Tail...> type;
};

template<int Begin, int Count>
inline typename make_int_range_type<Begin,Count>::type
make_int_range()
{ return typename make_int_range_type<Begin,Count>::type(); }


// the actual wrapper ...

template<class MemFunPtrType, MemFunPtrType PMF>
struct lua_mem_func_wrapper;

template<class Clazz, class ReturnType, class...Args, ReturnType(Clazz::*PMF)(Args...)>
struct lua_mem_func_wrapper<ReturnType(Clazz::*)(Args...),PMF> {
    static int doit(lua_State* L) {
        return doit_impl(L,make_int_range<2,sizeof...(Args)>());
    }
private:
    template<int...Indices>
    static int doit_impl(lua_State* L, int_pack<Indices...>) {
        luaU_push<ReturnType>(L,
            (luaW_check<Clazz>(L, 1)->*PMF)(
                luaU_check<Args>(L, Indices)...
            )
        );
        return 1;
    }
};

#define GET_MEM_FUN_WRAPPER(...) &lua_mem_func_wrapper<decltype(__VA_ARGS__),__VA_ARGS__>::doit


// testing ...

struct foo {
    int baz(int, float);
};

void test() {
    auto* ptr = GET_MEM_FUN_WRAPPER(&foo::baz);
}

This code compiles under G++ 4.6.1 using the options -c --std=c++0x. To see whether it really does what you want, please test it ...

Georg Fritzsche

Reusing the indices generation code from this answer and ignoring the function call to Func (don't know how exactly this is intended to be used), this is how it could look like:

template <typename T, typename U, U (T::*Func)(), 
          typename... Args, size_t... Idx>
int luaU_func_impl(lua_State* L, Collection<Idx...>)
{
   luaU_push<int>(L, luaW_check<U>(L, 1), luaU_check<Args>(L, Idx+2)...);
   return 1;
}

template <typename T, typename U, U (T::*Func)(), typename... Args>
int luaU_func(lua_State* L)
{
   typename GenerateCollection<Args...>::type Indices;
   return luaU_func_impl<T, U, Func, Args...>(L, Indices);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!