短整数上的 G++ abs() 似乎将其变成了双精度数?

Posted

技术标签:

【中文标题】短整数上的 G++ abs() 似乎将其变成了双精度数?【英文标题】:G++ abs() on a short int appears to turn it into a double? 【发布时间】:2011-11-22 12:20:00 【问题描述】:

如果存在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&lt;&lt;1) - ((angle*(std::abs&lt;int&gt;(angle)))&gt;&gt;B); 也是如此。

我使用的是 gcc 版本 4.6.1。包含的唯一外部标头是&lt;cmath&gt;&lt;cstdint&gt;。编译标志是-std=c++0x -Wall

【问题讨论】:

什么是T::storage_t::double_t?如果它是双精度的,则参数angle 将是函数内部的double,即使您将其传递给整数。如果您启用详细警告,您可能会收到有关它的警告。 如果我说angle是一个short int,而angle是一个声明为T::storage_t::double_t的函数参数,那么你当然可以推断出angle是一个整数。查看错误消息,您会看到只涉及整数,只是为了清楚起见。名称 'double_t 来自于它的存储大小是 single_t 的两倍。 我很困惑以 double_t 结尾的类型是一个短整数。 通用调试提示:如果复合语句的错误信息让您感到困惑,请将其拆开。通过这种方式,您会收到更有意义的信息。 【参考方案1】:

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 的返回值。

事实上,在g++中使用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);) 应该可以解决此问题。

【讨论】:

非常有帮助。我认为当我简单地包含&lt;cstdlib&gt; 而不是&lt;cmath&gt; 时,我的问题得到了解决,正如另一个答案所示。事实证明,如果我将两者都包括在内,问题会再次出现,原因是您概述的。您的解决方案在模板情况下有点混乱,例如在我原来的问题中。简单地将模板参数转换为 int 并不是很动态。我目前直接使用__builtin_abs(),它不是很便携。 作为模板函数的结果,std::abs&lt;int&gt;(int) 也返回double。疯狂。【参考方案2】:

std::abs() 函数不是 C++ 中的模板;只为不同类型提供了几个重载。整数类型在标题&lt;cstdlib&gt; 中。请参阅http://www.cplusplus.com/reference/clibrary/cstdlib/abs/ 和http://www.cplusplus.com/reference/clibrary/cmath/abs/ 了解更多信息。

【讨论】:

哇,如果您不小心,这种细节就会溜走。感谢您的关注! (顺便说一句,没有什么能阻止你简单地删除答案中让我的问题出错的部分,将来没有人会对阅读它感兴趣。) 会的。我是在这个网站上发布答案的新手,所以我不确定正确的礼仪是什么。【参考方案3】:

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

如果你真的需要同时包含这两个文件(你需要系统、malloc...和所有数学函数)快速而肮脏的解决方法是打开标题并在 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 函数并摆脱那个讨厌的错误。

我希望这会对某人有所帮助,我很抱歉这么长的帖子。

【讨论】:

以上是关于短整数上的 G++ abs() 似乎将其变成了双精度数?的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地从 Android 上的资源中获取短数组?

由于添加了双引号,json对象变成了字符串?

c语言浮常对13

在 std::abs 函数上

线段上格点的个数

c语言声明函数函数19