如果存在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()
不是模板,而是一组重载函数。根据标准,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
。
事实上,在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函数并消除这个讨厌的错误,您需要注释这行。
我希望这能帮助到一些人,我很抱歉写了这么长的一篇文章。