2013-10-28 1 views
2

나는 가변성 템플릿을 골치 덩어리로 만들려고 노력하고있다. 나는 그들이 존재한다는 것을 알고 있지만 새로운 기능으로 뒤죽박죽하려고합니다. 현재 VS2013 시험판이 작동 중입니다. 나는 C++ 측에서 루아 함수를 호출하는데 필요한 정보를 감싸는 펑터 클래스를 만들었다. 그러나, 나는 삶의 압축을 풀고 작동하도록 스택에 변수를 푸시하기 위해 만든 템플릿 기능을 얻을 수 없습니다. 나는 그물에있는 모든 예제를 찾아서 함수 템플릿의 값을 푸는 방법을 모든면에서 찾아 보았습니다. 나는 분명히 뭔가를 놓친다. 내가 주목 한 모든 예는 & & 이동 참조를 취했습니다. 그게 요구 사항입니까?C++ 11 가변 인자 템플릿이 함수에서 인자를 풀다. ​​

/* 
These functions push an item onto the lua stack 
*/ 
template<typename T> inline void lua_push(lua_State* L,T&& t){ static_assert(false,  "Unsupported Type! Cannot set to lua stack"); } 
template<> inline void lua_push<lua_CFunction>(lua_State* L,lua_CFunction&& func){  assert(L != nullptr && func != nullptr); lua_pushcfunction(L, func); } 
template<> inline void lua_push<double>(lua_State* L,double&& d){ assert(L != nullptr); lua_pushnumber(L, d); } 
template<> inline void lua_push<int>(lua_State* L,int&& i){ assert(L != nullptr); lua_pushinteger(L, i); } 
template<> inline void lua_push<bool>(lua_State* L,bool&& b){ assert(L != nullptr); lua_pushboolean(L, b); } 
template<> inline void lua_push<std::string>(lua_State* L,std::string&& s){ assert(L != nullptr); lua_pushlstring(L, s.c_str(), s.size()); } 
template<> inline void lua_push<const char*>(lua_State* L,const char*&& s){ assert(L != nullptr); lua_pushstring(L, s); } 

는 그럼 다음은 수정이다이 클래스

template<typename Return,typename... Args> class LuaFunctor{}; 
/* 
    A Lua function that will return a single value. 
*/ 
template<typename Return,typename... Args> class LuaFunctor<Return(Args...)> 
{ 
private: 
    //The lua state the function exists on 
    lua_State* m_luaState; 
    //Name of the function to be called in lua 
    std::string m_FunctionName; 
public: 
    //Return typedef 
    typedef Return return_type; 
    //The number of arguments the functor accepts 
    static const int arguments = sizeof...(Args); 
    //Constructors 
    inline LuaFunctor(lua_State* L,const std::string& name) : m_luaState(L), m_FunctionName(name) {} 
    inline LuaFunctor(lua_State* L,const char* name) : m_luaState(L), m_FunctionName(name) {} 
    //Function call overload that allows the functor to act like a function call of luascript 
    inline Return operator()(Args&&... args) 
    { 
     //Assert that the function name does exist and luaState is pointing to something hopefully meaningful 
     assert(m_luaState != nullptr && m_FunctionName.size() != 0); 
     //Set the function 
     lua_getglobal(m_luaState, m_FunctionName.c_str()); 
     //Verify Lua function is pushed onto the stack 
     assert(lua_isfunction(m_luaState, -1)); 
     //If arguments exist push them onto the stack 
     if (sizeof...(Args) != 0) 
     { 
        /* 
         How do I unpack this????? 
         I want to unpack this into multiple functions 
         One for each type of argument. 
        */ 
      lua_push(m_luaState, std::forward<Args>(args))...; 
     } 
     //Call the function that is in lua 
     int status = lua_pcall(m_luaState, sizeof...(Args), 1, 0); 
     /* 
      If there was an error calling the function throw an exception 
      TODO: parse the error using luas builtin decode of the error for now just pass it on 
      TODO: create lua_exception 
     */ 
     if (status != 0) throw std::exception("Error calling lua function"); 
     //Return the value request by lua, error checking is built-in to the function to verify type 
     return lua_get<Return>(m_luaState); 
    } 
}; 
+0

위 코드를 어떻게 추가 할 수 있습니까? 성공적으로 컴파일합니까? 'lua_push'가'if (sizeof ... (Args)! = 0)'내부에 있다고 확신합니까? – greatwolf

+0

아니요 컴파일 중이 아닙니다. 나는 해결책을 발견했다. 'template 인라인 void lua_push (lua_State * L, 첫 번째, 나머지 ... 나머지) { \t lua_push (L, first); \t lua_push (L, 나머지 ...); }' 이 함수는 매번 올바른 유형을 잡아내는 lua_push를 재귀 적으로 호출합니다. 그럼 그냥'lua_push (L, args ...);와 두통이 필요 없다. – user2927848

+3

['int swallow [] int {0, (lua_push (L, args), 0) ...};'] (http://stackoverflow.com/a/15062302/500104) – Xeo

답변

4

에 압축을 해제합니다. 재귀 함수 호출. 내가 읽었던 모든 종류의 해킹을 시도했지만 이것은 깨끗하고 간단하다.

/* 
    These functions push an item onto the lua stack 
*/ 
template<typename First, typename... Rest> inline void lua_push(lua_State* L,First first,Rest... rest) 
{ 
    lua_push(L, first); 
    lua_push(L, rest...); 
} 
template<typename T> inline void lua_push(lua_State* L, T t){ static_assert(false, "Invalid type attemptiing to be pushed onto lua stack!"); } 
template<> inline void lua_push<lua_CFunction>(lua_State* L, lua_CFunction func){ assert(L != nullptr && func != nullptr); lua_pushcfunction(L, func); } 
template<> inline void lua_push<double>(lua_State* L, double d){assert(L != nullptr); lua_pushnumber(L, d); } 
template<> inline void lua_push<int>(lua_State* L, int i){ assert(L != nullptr); lua_pushinteger(L, i); } 
template<> inline void lua_push<bool>(lua_State* L, bool b){ assert(L != nullptr); lua_pushboolean(L, b); } 
template<> inline void lua_push<std::string>(lua_State* L, std::string s){assert(L != nullptr); lua_pushlstring(L, s.c_str(), s.size()); } 
template<> inline void lua_push<const char*>(lua_State* L,const char* s){ assert(L != nullptr); lua_pushstring(L, s); } 

코드가 완벽하게 작동합니다.

template<typename Return,typename... Args> class LuaFunctor<Return(Args...)> 
{ 
private: 
    //The lua state the function exists on 
    lua_State* m_luaState; 
    //Name of the function to be called in lua 
    std::string m_FunctionName; 
public: 
    //Return typedef 
    typedef Return return_type; 
    //The number of arguments the functor accepts 
    static const int arguments = sizeof...(Args); 
    //Constructors 
    inline LuaFunctor(lua_State* L,const std::string& name) : m_luaState(L), m_FunctionName(name) {} 
    inline LuaFunctor(lua_State* L,const char* name) : m_luaState(L), m_FunctionName(name) {} 
    //Function call overload that allows the functor to act like a function call of luascript 
    inline Return operator()(Args... args) 
    { 
     //Assert that the function name does exist and luaState is pointing to something hopefully meaningful 
     assert(m_luaState != nullptr && m_FunctionName.size() != 0); 
     //Set the function 
     lua_getglobal(m_luaState, m_FunctionName.c_str()); 
     //Verify Lua function is pushed onto the stack 
     assert(lua_isfunction(m_luaState, -1)); 
     //If arguments exist push them onto the stack 
     if (sizeof...(Args) != 0) lua_push(m_luaState, args...); 
     //Call the function that is in lua 
     int status = lua_pcall(m_luaState, sizeof...(Args), 1, 0); 
     /* 
      If there was an error calling the function throw an exception 
      TODO: parse the error using luas builtin decode of the error for now just pass it on 
      TODO: create lua_exception 
     */ 
     if (status != 0) 
     { 
      report_errors(status); 
      throw std::exception("Error calling lua function"); 
     } 
     //Return the value request by lua, error checking is built-in to the function to verify type 
     return lua_get<Return>(m_luaState); 
    } 
}; 
+0

'템플릿 인라인 void lua_push (lua_State * L, T t)'를 제거하고 간단한 비 템플릿 함수'inline void lua_push (lua_State * L, lua_CFunction func) {/ * implementation * /}'을 사용할 수 있습니다. '클래스 내에서''inline'은 불필요합니다. – Jarod42

+0

예, 코드를 약간 지울 수 있으며 완료되지 않았습니다.() 연산자의 assert는 결국 다른 것들을 호출하고 lua_State에 대한 smart_prt 검사를 가지므로 더 고급 디버그 검사를위한 장소 홀더가됩니다. 그래도 인라인을 없애 버릴 수있었습니다. – user2927848

1

가장 쉬운 방법은 lua_push을 여러 오버라이드로 변경하는 것입니다.

일부 사본 또는 이동식을 반환하도록하십시오 (bool 또는 struct nothing{};). 그런 다음

:

그들 모두를 호출
auto sink[]={lua_push(m_luaState, std::forward<Args>(args))...}; 

.