g++ abs()在短整型上似乎将其转换为双精度类型



如果存在std::abs(angle),则无法编译以下代码。本例中angle的类型为short int

template <class T>
typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t &angle) {
  const int B = (sizeof(typename T::storage_t::single_t)*8) - 2;
  return (angle<<1) - ((angle*(std::abs(angle)))>>B);
}

仔细查看消息可以验证angle实际上是short int。但是,如果我正确阅读错误,GCC将其转换为double .

math.hpp: In function ‘typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t&) [with T = Fixed<_t<signed char, short int> >, typename T::storage_t::single_t = signed char, typename T::storage_t::double_t = short int]’:
vector.hpp:106:30:   instantiated from ‘void Vector2<T>::FastRotate(const single_t&) [with T = Fixed<_t<signed char, short int> >, Vector2<T>::single_t = signed char]’
test.cpp:9:18:   instantiated from here
math.hpp:11:52: error: invalid operands of types ‘__gnu_cxx::__enable_if<true, double>::__type {aka double}’ and ‘const int’ to binary ‘operator>>’

这是怎么回事?甚至return (angle<<1) - ((angle*(std::abs<int>(angle)))>>B);也是如此。

我使用gcc版本4.6.1。唯一包含的外部头文件是<cmath><cstdint>。编译标志为-std=c++0x -Wall

abs()不是模板,而是一组重载函数。根据标准,intlongfloatdoublelong double应该存在过载。但是short的重载不存在。但由于shortint的转换顺序只是一个提升,short到其他重载类型的转换顺序都是转换,所以应该选择int的重载。

但是在g++(我的版本4.5.2)中,一个非标准模板被添加到cmath:

template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
    double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }

该模板接受除intlong以外的所有内置整型,返回值为double

事实上,在c++中使用unsigned int类型也会产生这样的错误:

#include <cstdlib>
#include <cmath>
int main() {
    unsigned int i,j;
    i=0;
    j=std::abs(i)>>2;
    return 0;
}

显式地将其转换为int (std::abs((int)i);)应该可以解决这个问题。

std::abs()函数在c++中不是模板;只是为不同的类型提供了几个重载。整型的类型在头文件<cstdlib>中。详见http://www.cplusplus.com/reference/clibrary/cstdlib/abs/和http://www.cplusplus.com/reference/clibrary/cmath/abs/

我知道这个帖子很久以前就已经回答了,但我只是想给出另一个应该帮助别人的观点。我的问题是QT和mingw,总是当我用boost或其他一些使用cmath和cstdlib的库构建时,我得到了这个错误。一段时间后,我对这个错误非常恼火,我决定对这两个文件做一些研究。我完全同意fefe和他的答案,但只有在你的程序或库中使用它才能解决问题,并且你从一开始就知道什么是问题,而这不是我的问题。

如果你真的需要同时包含这两个文件(你需要system, malloc…所有的数学函数)快速而肮脏的修复是打开header,在106行(在我的计算机上)你会看到这样的东西:

    namespace std _GLIBCXX_VISIBILITY(default)
    {
    _GLIBCXX_BEGIN_NAMESPACE_VERSION
      using ::div_t;
      using ::ldiv_t;
      using ::abort;
      //using ::abs;
      using ::atexit;
      using ::atof;
      using ::atoi;
      using ::atol;
      using ::bsearch;
      using ::calloc;
.
.
.

从上面的代码中可以看到,cstdlib在std命名空间中有函数abs,为了启用cmath abs函数并消除这个讨厌的错误,您需要注释这行。

我希望这能帮助到一些人,我很抱歉写了这么长的一篇文章。

最新更新