次の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)
ヘッダー_<math.h>
_は、C std libヘッダーです。グローバル名前空間で多くのものを定義します。ヘッダー_<cmath>
_は、そのヘッダーのC++バージョンです。名前空間std
で本質的に同じものを定義します。 (C++バージョンにはいくつかの関数のオーバーロードが付属しているなど、いくつかの違いがありますが、それは重要ではありません。)ヘッダー_<cmath.h>
_は存在しません。
ベンダーは、本質的に同じヘッダーの2つのバージョンを維持することを望んでいないため、それらのうちの1つだけを背後で持つ異なる可能性を考え出しました。多くの場合、それはCヘッダーです(C++コンパイラーはそれを解析できますが、反対は機能しません)ので、C++ヘッダーにはそれが含まれ、名前空間std
にすべてを取り込みます。または、_namespace 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()
です)。ただし、上記の実装のトリックによると、可能性があります。そのようなコードを後で移植する(または、これを許可しないベンダーの次のバージョンでコンパイルしようとする)ことはvery退屈なので、これに注意する必要があります。
要約すると、math.h
はC
からのもので、10年以上前に作成されました。 math.hでは、その原始的な性質により、abs()
関数は整数型に対してのみ「本質的に」あり、doubleの絶対値を取得したい場合は、fabs()
を使用する必要がありました。 。 C++が作成されたとき、math.h
を取り、cmath
にしました。 cmath
は基本的にmath.hですが、C++向けに改善されています。 fabs()
とabsを区別するなどの改善が行われ、double型と整数型の両方に対してabs()
が作成されました。要約すると、math.hを使用して整数にabs()
を使用し、doubleにfabs()
を使用するか、cmathを使用してすべてにabsを使用します(簡単で推奨)。
これが同じ問題を抱えている人を助けることを願っています!
Abs()の代わりにfabs()を使用します。これは整数ではなくfloatの場合と同じです。