2012-07-21 28 views
5

Đối với dự án hiện tại của tôi, tôi đã viết rất nhiều C/C++ cho trình bao bọc Lua. Một số lượng lớn trong số này là setters đơn giản và thu khí, vì vậy tôi cố gắng viết một số mẫu mà làm cho nó dễ dàng để tạo ra những, như vậy:Làm thế nào để sử dụng các mẫu variadic để tạo một hàm bao hàm Lua chung?

//  Class  Return  Field 
template <typename T, typename U, U T::*Member> 
int luaU_get(lua_State* L) 
{ 
    T* obj = luaW_check<T>(L, 1); 
    luaU_push<U>(L, obj->*Member); 
    return 1; 
} 

static luaL_reg Foo_Table[] = 
{ 
    ... 
    // Now I can just use this generic template to avoid 
    // writing simple getter functions 
    { "getbar", luaU_get<Foo, Bar, &Foo::bar> }, 
    ... 
}; 

Tôi muốn làm điều gì đó tương tự cho giấy gói chức năng đơn giản cho các chức năng tùy ý quá. Ví dụ, nó sẽ được tốt đẹp để có thể làm điều này:

template <typename T, typename U, U (T::*Func)(), typename... Args> 
int luaU_func(lua_State* L) 
{ 
    // ...? 
} 

static luaL_reg Foo_Table[] = 
{ 
    ... 
    { "baz", luaU_func<Foo, int, &Foo::baz, int, float> }, 
    ... 
}; 

Ý tưởng là các mẫu có hiệu quả bật ra được điều này khi biên soạn:

int luaU_func(lua_State* L) 
{ 
    luaU_push<int>(L, luaW_check<Foo>(L, 1)->baz(luaU_check<int>(L, 2), luaU_check<float>(L, 3))); 
    return 1; 
} 

tôi đã cố gắng chỉ sử dụng ... expander, vấn đề đối với tôi là các giá trị chỉ số nguyên để ánh xạ tới các đối số thích hợp. Tôi không thể nghĩ ra cách để họ làm việc đúng. Một điều như vậy thậm chí có thể?

(có một chút kỳ diệu xảy ra ở đây đã, tôi đã viết một số giấy gói templated cho những thứ như lua_push và lua_check Tất cả những giấy gói hiện tại có thể được tìm thấy here.)

+0

Bạn đã xem [luabind] (http://www.rasterbar.com/products/luabind.html) chưa? –

+0

Bạn có đề xuất tôi sử dụng luabind không? Hay họ đã giải quyết một vấn đề tương tự mà tôi có thể sử dụng để tham khảo? (Tôi không quan tâm đến việc sử dụng luabind cho dự án của tôi vì một số lý do.) – Alex

+1

Tôi chỉ không chắc chắn nếu bạn biết về nó. Dù sao, đối với các đối số & vấn đề chỉ số, [đây là ý tưởng cơ bản] (http://stackoverflow.com/a/8028333/168225). –

Trả lời

5

Bí quyết là để khai thác trích lập luận mẫu bằng một phần một lớp chuyên mẫu có chứa trình bao bọc ction:

// 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); 
} 

Mã này biên dịch dưới G ++ 4.6.1 bằng cách sử dụng tùy chọn -c --std = C++ 0x. Để xem liệu nó có thực sự thực hiện những gì bạn muốn hay không, hãy thử nghiệm nó ...

+0

Tôi chỉ thử nghiệm này và nó xuất hiện để làm việc chính xác như tôi muốn, cảm ơn bạn rất nhiều: D Thấy câu trả lời này làm cho tôi cảm thấy ít xấu mà tôi không thể tìm ra bản thân mình. – Alex

2

Tái sử dụng mã thế hệ chỉ số từ this answer và bỏ qua các cuộc gọi chức năng để Func (không biết làm thế nào chính xác này được thiết kế để được sử dụng), đây là cách nó có thể trông giống như:

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

Điều này không hoạt động, ít nhất là không như bạn hiển thị ở đây ... Con trỏ hàm 'U (T :: * Func)()' không nhận bất kỳ đối số nào. – Alex

+0

Tôi chỉ sử dụng những gì bạn đã hiển thị ở trên - bạn muốn sử dụng loại chức năng nào? –

+0

Bất kỳ chức năng thành viên nào có thể có các đối số tùy ý - ví dụ của tôi không hoạt động, đó là vấn đề tôi đang cố giải quyết. – Alex

Các vấn đề liên quan