模板强制类型转换问题

当我尝试将类型为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 typechar*’ to type ‘float’

原文链接 https://stackoverflow.com/questions/1516845

点赞
stackoverflow用户172531
stackoverflow用户172531

请避免使用 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,你就会得到一个编译时错误。我希望你能理解。

2009-10-04 16:50:12
stackoverflow用户179930
stackoverflow用户179930

我对 Lua 不太熟悉,但在这种情况下我认为并不重要...

lua_toString 返回的显然是 char* 类型,这意味着你得到的是值的地址,并且尝试将该地址转换为浮点数类型。看看 strtod 如何更正确地完成这个操作,或者像 sellibitze 指出的那样,使用 stringstream。

2009-10-04 17:08:35
stackoverflow用户127893
stackoverflow用户127893

我之前从未接触过 lua 或它的引擎,但我觉得你在误用 lua_tostring。它的签名如下:

const char *lua_tostring (lua_State *L, int index);

显然,这个函数返回一个 const char*。如果 T == int,C/C++ 允许从指针转换为整数的 reinterpret_cast。在 T == float 的情况下,这种转换是无意义的。我认为你需要拿到返回的 c 字符串,然后使用 atoiatof 转换成数字,具体取决于类型。问题出在这里:

res = (T)lua_tonumber(luaState, -1);

因为如我们所说,指针可以在 C/C++ 中以有意义的方式转换为 整数,但不能转换为 浮点数

2009-10-04 17:11:26
stackoverflow用户34509
stackoverflow用户34509

你需要在编译时分支。将你的模板内容更改为以下内容:

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

专业化将确定使用字符串和哪种数字转换的“配置”。

2009-10-04 18:53:06
stackoverflow用户173806
stackoverflow用户173806

使用memcpy()进行赋值将避免编译器错误。

char *str = lua_tostring(luaState, -1)
memcpy(&res, &str, sizeof(res));

但是,在调用lua_pop()之后,lua_tostring()返回的字符串将不再有效。字符串确实需要复制到另一个缓冲区中。

2009-10-06 20:07:48
stackoverflow用户88888888
stackoverflow用户88888888

尽管Lua网站这样说,而且这也有逻辑意义,但是测试时,我发现指针即使在状态关闭后仍然有效。虽然他说得对,如果想在Lua函数返回后继续使用字符串,应该复制它,但这可能不是他的问题。

2009-10-06 20:55:48