不明确的过载调用abs(双)

时间:2009-09-03 15:13:43

标签: c++ std cmath

我有以下C ++代码:

#include <math.h>
#include <cmath.h>      // per http://www.cplusplus.com/reference/clibrary/cmath/abs/

// snip ...

if ( (loan_balance < 0) && (abs(loan_balance) > loan_payment) ) {
    ...
}

make爆炸:

error: call of overloaded 'abs(double)' is ambiguous

也感兴趣:

/usr/include/stdlib.h:785: note: candidates are: int abs(int)

如何指定编译器需要在cmath.h中调用可以处理浮点数的abs()?

编译器信息(不确定这是否重要):

[some_man@some_box ~/some_code]#  gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr    /share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)

4 个答案:

答案 0 :(得分:46)

标头<math.h>是一个C std lib标头。它在全局命名空间中定义了很多东西。标头<cmath>是该标头的C ++版本。它在名称空间std中定义了基本相同的东西。 (存在一些差异,例如C ++版本带有某些函数的重载,但这并不重要。)标题<cmath.h>不存在。

由于供应商不想维护基本相同标题的两个版本,因此他们提出了在幕后只有一个版本的不同可能性。通常,这是C头(因为C ++编译器能够解析它,而相反的方法不起作用),而C ++头只包含它并将所有内容拉入命名空间std。或者有一些宏观魔法用于解析相同的标题,包括或不包含namespace std。对此添加,在某些环境中,如果标头没有文件扩展名(如编辑器无法突出显示代码等),则会很麻烦。因此,某些供应商会<cmath>成为一个单行,包括一些带有.h扩展名的其他标题。或者有些会映射所有包含匹配<cblah><blah.h>的内容(通过宏魔术,在定义__cplusplus时成为C ++标头,否则成为C标头)或{{1} } 管他呢。

这就是为什么在某些平台上,包括<cblah.h>这样不应该存在的平台,最初会成功的,尽管它可能会使编译器在以后出现故障。

我不知道你使用哪个std lib实现。我想这是GCC附带的那个,但我不知道,所以我无法解释你的情况究竟发生了什么。但它肯定是上述特定于供应商的黑客之一,你包括一个你不应该自己包含的标题。也许它是<cmath.h>映射到<cmath>的那个,它带有一个你没有定义的特定(一组)宏,所以你最终得到了这两个定义。

但请注意,此代码仍不应编译:

<cmath.h>

全局命名空间中不应该有#include <cmath> double f(double d) { return abs(d); } (它是abs())。然而,根据上述实施技巧,可能存在。稍后移植这样的代码(或者只是尝试用你的供应商的下一个版本编译它不允许这样做)可能非常乏味,所以你应该留意这一点。

答案 1 :(得分:34)

归结为:math.h来自C,是在10年前创建的。在math.h中,由于其原始性质,abs()函数“基本上”仅适用于整数类型,如果要获得double的绝对值,则必须使用fabs()。 创建C ++时,它花了math.h并将其设为cmathcmath本质上是math.h,但对C ++进行了改进。它改进了诸如必须区分fabs()和abs之类的内容,并且仅针对双精度和整数类型创建了abs()。 总结如下: 使用math.h并使用abs()表示整数,fabs()表示双精度数 要么 使用cmath,只需要abs就可以了(更容易和推荐)

希望这有助于任何遇到同样问题的人!

答案 2 :(得分:15)

使用fabs()而不是abs(),它是相同的但是对于浮点数而不是整数。

答案 3 :(得分:0)

在我的情况下,我使用labs()而不是abs()解决了问题。