67

次の 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)

float を処理できる 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

4 に答える 4

55

ヘッダー<math.h>は C std lib ヘッダーです。グローバル名前空間で多くのものを定義します。ヘッダー<cmath>は、そのヘッダーの C++ バージョンです。namespace で本質的に同じものを定義しますstd。(C++ バージョンにはいくつかの関数のオーバーロードが付属しているなど、いくつかの違いがありますが、それは問題ではありません。) ヘッダー<cmath.h>は存在しません。

ベンダーは、本質的に同じヘッダーの 2 つのバージョンを維持したくないため、舞台裏で 1 つだけを保持するというさまざまな可能性を考え出しました。多くの場合、それは C ヘッダーであり (C++ コンパイラはそれを解析できますが、逆は機能しないため)、C++ ヘッダーはそれをインクルードし、すべてを namespace にプルしますstdnamespace stdまたは、ラップされているかどうかに関係なく、同じヘッダーを解析するためのマクロマジックがあります。これに加えて、一部の環境では、ヘッダーにファイル拡張子がない場合 (エディターがコードを強調表示できないなど) は厄介です。そのため、一部のベンダーは、拡張子<cmath>を持つ他のヘッダーを含むワンライナーでした。.hまたは、一致<cblah>するすべてのインクルードをマップする人もいます<blah.h>(マクロ マジックにより、__cplusplusが定義されている場合は C++ ヘッダーになり、それ以外の場合は C ヘッダーになります)<cblah.h>または何でも。

これが、存在しないはずの のようなものを含む一部のプラットフォームで最初は成功する理由です<cmath.h>が、後でコンパイラが見事に失敗する可能性があります。

どの std lib 実装を使用しているかわかりません。GCCに付属しているものだと思いますが、これはわかりません。そのため、あなたのケースで何が起こったのかを正確に説明することはできません. しかし、これは確かに、上記のベンダー固有のハックの 1 つと、自分で含めるべきではないヘッダーを含めたものです。おそらく、定義していない特定の (セットの) マクロに<cmath>マップされているため、両方の定義が作成された可能性があります。<cmath.h>

ただし、このコードはまだコンパイルされるべきではないことに注意してください。

#include <cmath>

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

abs()グローバル名前空間にがあってはなりません(それはstd::abs()です)。ただし、上記の実装のトリックに従って、存在する可能性があります。そのようなコードを後で移植する (または、これを許可しないベンダーの次のバージョンでコンパイルしようとするだけである) のは非常に面倒なので、注意してください。

于 2009-09-03T16:04:07.423 に答える
42

要約すると、math.hC10 年以上前に作成されたものです。math.h では、プリミティブな性質のため、このabs()関数は "本質的に" 整数型のみを対象としており、double の絶対値を取得する場合は を使用する必要がありましたfabs()。C++ が作成されたとき、それを取りmath.h、それを作成しましたcmathcmath基本的に math.h ですが、C++ 用に改良されています。fabs()と absを区別する必要があるなどの点が改善されabs()、double 型と integer 型の両方が作成されました。要約すると、次のいずれかです: math.h を使用abs()して整数に使用するかfabs()、double に使用するか、cmath を使用してすべてに abs を使用します (より簡単で推奨)。

これが同じ問題を抱えている人の助けになることを願っています!

于 2011-03-27T16:26:58.013 に答える
19

abs() の代わりに fabs() を使用してください。同じですが、整数ではなく浮動小数点数の場合です。

于 2011-09-14T11:00:50.300 に答える