当我尝试转换为类T的模板时,当T为float类型时,我似乎在下面的代码中出现错误。我已经意识到一种int函数正确,因为以下是有效的语法:
char* str = "3";
int num = (int)str;
浮动也是如此。我想知道是否有办法阻止g ++编译器在类型不匹配时出错,因此我可以使用RTTI方法typeid()来处理它。
class LuaConfig {
// Rest of code omitted...
// 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;
// WHERE THE PROBLEM IS:
if ( typeid(T) == typeid(int)
|| typeid(T) == typeid(float)
) {
std::cout << "AS NUM" << std::endl;
// Floats should fall in here, but never does because of the
// else clause failing at compile time.
res = (T)lua_tonumber(luaState, -1);
} else {
// TODO: Fails on float here, it should fall down the
// first branch (above). This branch should only be for string data.
std::cout << "AS STRING" << std::endl;
res = (T)lua_tostring(luaState, -1); // LINE THAT CAUSES ISSUE.
}
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; // This causes the error.
}
g ++抛出的错误是:
source/Main.cpp:128: error: invalid cast from type ‘char*’ to type ‘float’
答案 0 :(得分:2)
尽量避免使用C风格的演员表。如果你写(int)ptr,其中ptr是一些指针,这将是一个reinterpret_cast,这可能不是你想要的。要将数字转换为字符串并再返回,请查看各种常见问题解答一种方法是使用std::stringstream类。
C风格的演员阵容很危险,因为它可以用于很多事情,而且它的作用并不总是很明显。 C ++提供了替代方案(static_cast,dynamic_cast,const_cast,reinterpret_cast)和功能样式的转换,相当于静态转换。
在(int)ptr的情况下,它将指针转换为int,不是指针指向的数字的字符串表示。
您可能还想查看Boost's 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,则会出现编译时错误。我希望你明白这一点。
答案 1 :(得分:1)
您需要在编译时进行分支。将模板中的内容更改为以下内容:
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);
}
有几个alternative ways可以解决这个问题。为避免重复添加重载,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);
}
然后,专业化将确定应该使用字符串和数字转换的“配置”。
答案 2 :(得分:0)
我不熟悉Lua,但在这种情况下我认为不重要......
lua_toString的返回显然是char*
,这意味着您获取值的地址,然后尝试将该地址转换为浮点数。请查看strtod
以了解如何更正确地执行此操作,或者,正如sellibitze所指出的,使用字符串流。
答案 3 :(得分:0)
我以前从未接触过lua
或它的引擎,但在我看来,你误导了lua_tostring
。这是它的签名:
const char *lua_tostring (lua_State *L, int index);
显然,此函数返回const char*
。如果是T == int
,则C / C ++允许从reinterpret_cast
到pointer
的所谓int
。 T == float
的情况下,这种转换毫无意义。我认为您必须获取返回的c字符串,然后根据类型将其转换为使用atoi
或atof
的数字。问题发生在这里:
res = (T)lua_tonumber(luaState, -1);
因为正如我们所说,指针可以在C / C ++中以有意义的方式转换为integers
,与floats
不同。
答案 4 :(得分:0)
使用memcpy()进行赋值可以避免编译错误。
char *str = lua_tostring(luaState, -1)
memcpy(&res, &str, sizeof(res));
但是,lua_tostring()
返回的字符串在调用lua_pop()
后不再有效。该字符串确实需要复制到另一个缓冲区。
答案 5 :(得分:0)
尽管Lua网站说的是,并且它具有逻辑意义,但在测试时我发现指针在状态关闭后仍然有效。虽然他是对的,如果你想在Lua函数返回后保留它,你真的应该复制字符串,这可能不是他的问题。