模板强制类型转换问题
当我尝试将类型为float的T类模板强制转换时,似乎下面的代码出错了。我已经意识到int类型的函数是正确的,因为以下是有效的语法:
char* str = "3";
int num = (int)str;
对于float类型,不是这样的。我想知道是否有一种方式可以使g ++编译器不进行类型不匹配的错误,以便我可以使用RTTI方法typeid()处理它。
类LuaConfig {
//省略剩余代码...
//模板目前支持字符串和整数
template <class T> T getC(const char *key) {
lua_pushstring(luaState, key);
lua_gettable(luaState, -2);
if (!lua_isnumber(luaState, -1)) {
//抛出错误
std::cout << "NOT A NUMBER" << std::endl;
}
T res;
//问题所在:
if ( typeid(T) == typeid(int)
|| typeid(T) == typeid(float)
) {
std::cout << "AS NUM" << std::endl;
//浮点数应该落在这里,但从不落在这里
//else子句在编译时失败。
res = (T)lua_tonumber(luaState, -1);
} else {
//TODO:在这里失败float,它应该下降到第一支(上面)。
//此分支应仅用于字符串数据。
std::cout << "AS STRING" << std::endl;
res = (T)lua_tostring(luaState, -1); //导致故障的行。
}
std::cout << "OUT:" << res << std::endl;
lua_pop(luaState, 1);
return res;
}
}
int main (int argc,char * args []){
LuaConfig *conf = new LuaConfig();
std :: cout << conf-> getC <int>(“width”)<< std :: endl;
std :: cout << conf-> getC <float>(“width”)<< std :: endl; //这会导致错误。
}
g ++抛出的错误是:
source/Main.cpp:128: error: invalid cast from type ‘char*’ to type ‘float’
原文链接 https://stackoverflow.com/questions/1516845
我对 Lua 不太熟悉,但在这种情况下我认为并不重要...
lua_toString 返回的显然是 char*
类型,这意味着你得到的是值的地址,并且尝试将该地址转换为浮点数类型。看看 strtod
如何更正确地完成这个操作,或者像 sellibitze 指出的那样,使用 stringstream。
我之前从未接触过 lua
或它的引擎,但我觉得你在误用 lua_tostring
。它的签名如下:
const char *lua_tostring (lua_State *L, int index);
显然,这个函数返回一个 const char*
。如果 T == int
,C/C++ 允许从指针转换为整数的 reinterpret_cast
。在 T == float
的情况下,这种转换是无意义的。我认为你需要拿到返回的 c 字符串,然后使用 atoi
或 atof
转换成数字,具体取决于类型。问题出在这里:
res = (T)lua_tonumber(luaState, -1);
因为如我们所说,指针可以在 C/C++ 中以有意义的方式转换为 整数
,但不能转换为 浮点数
。
你需要在编译时分支。将你的模板内容更改为以下内容:
template<typename T> struct id { };
// template currently supports both string and int
template <class T> T getC(const char *key) {
lua_pushstring(luaState, key);
lua_gettable(luaState, -2);
if (!lua_isnumber(luaState, -1)) {
// throw error
std::cout << "NOT A NUMBER" << std::endl;
}
T res = getCConvert(luaState, -1, id<T>())
std::cout << "OUT:" << res << std::endl;
lua_pop(luaState, 1);
return res;
}
// make the general version convert to string
template<typename T>
T getCConvert(LuaState s, int i, id<T>) {
return (T)lua_tostring(s, i);
}
// special versions for numbers
float getCConvert(LuaState s, int i, id<int>) {
return (float)lua_tonumber(s, i);
}
int getCConvert(LuaState s, int i, id<float>) {
return (int)lua_tonumber(s, i);
}
有一些替代方案可以解决这个问题。为了避免不断添加重载,boost::enable_if
可能会有用。但是只要int和float只有两种特殊情况,我会保持简单,只重复调用lua_tonumber
。
另一个避免enable_if
和仍然避免重复重载的模式是引入类型标志层次结构 - 更改id
为以下方式,保持getC
中的代码与上面相同。如果有更多需要特殊处理的情况,我会使用这个:
template<typename T> struct tostring { };
template<typename T> struct tonumber { };
template<typename T> struct id : tostring<T> { };
template<> struct id<int> : tonumber<int> { };
template<> struct id<float> : tonumber<float> { };
现在需要在类模板之外定义id
,因为您无法在模板中显式专门化它。然后将辅助函数的重载更改为以下内容:
// make the general version convert to string
template<typename T>
T getCConvert(LuaState s, int i, tostring<T>) {
return (T)lua_tostring(s, i);
}
// special versions for numbers
template<typename T>
T getCConvert(LuaState s, int i, tonumber<T>) {
return (T)lua_tonumber(s, i);
}
专业化将确定使用字符串和哪种数字转换的“配置”。
使用memcpy()
进行赋值将避免编译器错误。
char *str = lua_tostring(luaState, -1)
memcpy(&res, &str, sizeof(res));
但是,在调用lua_pop()
之后,lua_tostring()
返回的字符串将不再有效。字符串确实需要复制到另一个缓冲区中。
尽管Lua网站这样说,而且这也有逻辑意义,但是测试时,我发现指针即使在状态关闭后仍然有效。虽然他说得对,如果想在Lua函数返回后继续使用字符串,应该复制它,但这可能不是他的问题。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
请避免使用 C 风格转型。如果你写下 (int)ptr,其中 ptr 是某个指针,那么这将是一种 reinterpret_cast,这可能不是你想要的。要将数字转换为字符串,或者将其转换回来,请查阅各种 FAQ。其中一种方法是使用 std::stringstream 类。
C 风格转型是危险的,因为它可以用于许多事情,而它所做的事情并不总是显而易见的。C++ 提供了替代方案(static_cast、dynamic_cast、const_cast、reinterpret_cast)以及等同于静态转型的函数风格转型。
对于 (int)ptr 这种情况,它会将 指针 转换为 int,而 不是 指针指向的数字的字符串表示。
你可能还想查看 Boost 的 lexical_cast。
编辑:不要使用 typeid 进行此操作。你完全可以在编译时处理这个问题:
template<typename T> struct doit; // no definition template<> struct doit<int> { static void foo() { // action 1 for ints } }; template<> struct doit<float> { static void foo() { // action 2 for floats } }; .... template<typename T> void blah(T x) { // common stuff doit<T>::foo(); // specific stuff // common stuff }
如果 T 既不是 int 也不是 float,你就会得到一个编译时错误。我希望你能理解。