Написание оболочки Lua, как вернуть значение из стека, используя метод, который может возвращать несколько типов?

#c #lua

#c #lua

Вопрос:

Может ли кто-нибудь объяснить мне, почему следующий код не работает, и предложить предложение относительно того, что я мог бы сделать, чтобы заставить его работать. Я открыт для использования Boost, но я бы предпочел этого не делать, если это возможно. Должно быть довольно очевидно, что я пытаюсь сделать из кода. Проблема в том, что я не знаю, какой тип будет возвращать метод до времени выполнения?

 template <typename T>
T getAs()
{
  if(typeid(T) == typeid(std::string))
return lua_tostring(lua, stackPos);

  if((typeid(T) == typeid(int)) || (typeid(T) == typeid(long)))
return lua_tointeger(lua, stackPos);

  if((typeid(T) == typeid(float)) || (typeid(T) == typeid(double)))
return lua_tonumber(lua, stackPos);

  if(typeid(T) == typeid(bool))
return lua_toboolean(lua, stackPos);
}
  

Часть сообщения об ошибке:

 In file included from ./luaStackResult.hpp:32:
./luaStackItem.hpp:53:9: error: no viable conversion from 'lua_Integer' (aka 'long') to 'std::basic_string<char>'
    return lua_tointeger(lua, stackPos);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/lua.h:320:28: note: expanded from macro 'lua_tointeger'
#define lua_tointeger(L,i)    lua_tointegerx(L,i,NULL)
                            ^~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:20:15: note: in instantiation of function template specialization 'cppLua::luaStackItem::getAs<std::basic_string<char> >' requested here
cout << I.getAs<std::string>() << endl;
  

Ответ №1:

Шаблоны — это концепция времени компиляции, а не концепция времени выполнения. В двоичном файле нет шаблонного кода. Поэтому ваши GETAS не могут компилироваться как есть: иногда вы не можете возвращать один тип, а иногда другой тип. Однако вы могли бы сделать что-то вроде

 // define general template:
template <typename T> T getAs();

// define specializations for different returned types: 
template <> std::string getAs<std::string>() { return lua_tostring(lua, stackPos); }
template <> int         getAs<int>()         { return lua_tointeger(lua, stackPos); }
template <> float       getAs<float>()       { return lua_tonumber(lua, stackPos); }
template <> bool        getAs<bool>()        { return lua_toboolean(lua, stackPos); }
  

Затем, когда вы делаете

 cout << getAs<std::string>() << endl;
  

компилятор выберет правильную специализацию. Среда выполнения будет содержать только экземпляры шаблонов getAs , которые использовались в вашем исходном коде.