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

后端 未结 2 1410
感情败类
感情败类 2020-12-30 12:52

For my current project, I\'ve been writing a lot of C/C++ to Lua wrappers. A large number of these are simple setters and getters, so I managed to write some templates that

相关标签:
2条回答
  • 2020-12-30 13:21

    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 ...

    0 讨论(0)
  • 2020-12-30 13:32

    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);
    }
    
    0 讨论(0)
提交回复
热议问题