短整数上的 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<<1) - ((angle*(std::abs<int>(angle)))>>B);
也是如此。
我使用的是 gcc 版本 4.6.1。包含的唯一外部标头是<cmath>
和<cstdint>
。编译标志是-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()
不是模板,而是一组重载函数。根据标准,int
、long
、float
、double
、long double
的重载应该存在。但是short
的重载不存在。但是由于short
到int
的转换序列只是一个提升,而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);
此模板将采用除int
和long
之外的所有内置整数类型,并给出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);
) 应该可以解决此问题。
【讨论】:
非常有帮助。我认为当我简单地包含<cstdlib>
而不是<cmath>
时,我的问题得到了解决,正如另一个答案所示。事实证明,如果我将两者都包括在内,问题会再次出现,原因是您概述的。您的解决方案在模板情况下有点混乱,例如在我原来的问题中。简单地将模板参数转换为 int
并不是很动态。我目前直接使用__builtin_abs()
,它不是很便携。
作为模板函数的结果,std::abs<int>(int)
也返回double
。疯狂。【参考方案2】:
std::abs()
函数不是 C++ 中的模板;只为不同类型提供了几个重载。整数类型在标题<cstdlib>
中。请参阅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() 似乎将其变成了双精度数?的主要内容,如果未能解决你的问题,请参考以下文章