【问题标题】:Ambiguous overload call to abs(double)对 abs(double) 的模棱两可的重载调用
【发布时间】:2009-09-03 15:13:43
【问题描述】:

我有以下 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)

【问题讨论】:

标签: c++ std cmath


【解决方案1】:

标头 &lt;math.h&gt; 是 C 标准库标头。它在全局命名空间中定义了很多东西。标头 &lt;cmath&gt; 是该标头的 C++ 版本。它在命名空间std 中定义了基本相同的东西。 (有一些区别,比如 C++ 版本带有一些函数的重载,但这没关系。)标题 &lt;cmath.h&gt; 不存在。

由于供应商不想维护本质上相同的标头的两个版本,因此他们提出了不同的可能性,即只在幕后使用其中的一个。通常,这是 C 头文件(因为 C++ 编译器能够解析它,而相反的则不起作用),而 C++ 头文件只包含它并将所有内容拉入命名空间std。或者有一些宏魔法来解析相同的标头,无论是否包裹namespace std。除此之外,在某些环境中,如果标头没有文件扩展名(例如编辑器无法突出显示代码等),这会很尴尬。所以一些供应商会让&lt;cmath&gt; 成为一个单行,包括一些其他带有.h 扩展名的标题。或者有些人会将所有包含匹配的&lt;cblah&gt; 映射到&lt;blah.h&gt;(通过宏魔术,当__cplusplus 被定义时,它成为C++ 头文件,否则成为C 头文件)或&lt;cblah.h&gt; 或其他。

这就是为什么在某些平台上,包括像 &lt;cmath.h&gt; 这样的不应该存在的东西,最初会成功,尽管它可能会在以后使编译器严重失败。

我不知道你使用哪个标准库实现。我想它是 GCC 附带的,但我不知道,所以我无法准确解释你的情况发生了什么。但这肯定是上述供应商特定黑客之一的混合,并且您包含了一个您不应该包含自己的标题。也许这是&lt;cmath&gt; 映射到&lt;cmath.h&gt; 的地方,其中包含您尚未定义的特定(一组)宏,因此您最终得到了两个定义。

但是请注意,这段代码仍然不应该编译:

#include <cmath>

double f(double d)
{
  return abs(d);
}

全局命名空间中不应有abs()(它是std::abs())。但是,根据上述实现技巧,很可能会有。稍后移植此类代码(或者只是尝试使用您的供应商不允许这样做的下一个版本对其进行编译)可能会非常乏味,因此您应该注意这一点。

【讨论】:

    【解决方案2】:

    归结为:math.h 来自 C,创建于 10 多年前。在 math.h 中,由于其原始性质,abs() 函数“基本上”仅适用于整数类型,如果您想获得双精度数的绝对值,则必须使用 fabs()。 创建 C++ 时,它使用 math.h 并使其变为 cmathcmath 本质上是 math.h,但针对 C++ 进行了改进。它改进了诸如必须区分 fabs() 和 abs 之类的事情,并且只为双精度和整数类型创建了 abs()。 总之: 使用 math.h 并将 abs() 用于整数,fabs() 用于双精度数 或者 使用 cmath 并且对所有内容都使用 abs(更简单且推荐)

    希望这对遇到同样问题的人有所帮助!

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 这在std 命名空间中并不准确,其中absfloatdouble 等的重载。
      • 修复gcc6错误:重载'abs(uint32_t)'的调用不明确
      • @Sérgio 我认为你应该删除对 abs 的调用,因为 uint32_t 是无符号的。 (相反,您将 fabs(double) 的 uint32_t 隐式转换为 double,然后我假设将结果转换回整数!)
      • 我不记得我在哪里使用了这个补丁,我也找不到在哪里,我在谷歌上看过,但我同意你的看法......我想回顾一下这个 gcc6 修复谢谢。
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2011-06-30
        • 1970-01-01
        • 2016-12-27
        • 1970-01-01
        • 2021-12-04
        • 2019-09-13
        • 1970-01-01
        相关资源
        最近更新 更多