web-dev-qa-db-ja.com

C ++標準では、 `<cmath>`にある `abs`オーバーロードを定義するために` #include <math.h> `が必要ですか?

C++標準では、Cの_<cmath>_ヘッダーの一部ではないいくつかのオーバーロードされた関数が_<math.h>_ヘッダーに定義されています(Cにはオーバーロードがないため)。これらの中には、float abs(float)double abs(double)long double abs(long double)、およびdouble abs(Integral)があります。一方、absはC _<math.h>_ではまったく定義されておらず(代わりに_<stdlib.h>_にあります)、唯一の署名はint abs(int)です。

私のシステムでは、C++プログラムでC++コンパイラを使用する場合、_#include <math.h>_は、グローバル名前空間またはabsのいずれにおいてもC++ stdオーバーロードを提供しません。一方、_#include <cmath>_は_std::abs_を定義します。

これは私が期待していることです。C関数を取得するためにCバージョンを含め、C++関数を取得するためにC++バージョンを含めます。 この回答 @ visitorによる同じことについて言及しています。

ただし、ユーザー@ Cheers-and-hth-Alfは、「それぞれが_name.h_の形式の名前を持つすべてのCヘッダーは、それぞれの名前が配置されているかのように動作するため、これは標準違反であると主張しています。対応するcnameヘッダーによる標準ライブラリ名前空間では、グローバル名前空間スコープ内に配置されます。」 (このセクションD.5.2は、C++ 03、C++ 11、およびC++ 14の間で大幅に変更されていないようです。)

プラットフォームの機能を確認するのは簡単です。何が起こるかを確認してください。

_#include <math.h>

int main() {
    abs(1.2);
    return 0;
}
_

absが宣言されていない場合、_<math.h>_にはC++関数は含まれません。

コンパイルする場合は、_<stdio.h>_を含めてprintf("%g\n", abs(1.2));を追加してみてください。フォーマットの不一致について文句を言うか、1を出力する場合は、_<math.h>_にC int abs(int)関数が含まれます(通常は_<stdlib.h>_にあります)。 (_<iostream>_およびその他のC++ヘッダーは、_<cstdlib>_をプルして問題を混乱させる傾向があるため、避けるのが最善です。)

これが私が見つけたものです:

GNU libstdc ++

_$ g++ -Wall -Wextra abs2.cc -o abs2
abs2.cc: In function 'int main()':
abs2.cc:5:22: error: 'abs' was not declared in this scope
  std::cout << abs(1.2) << '\n';
_

この件に関するlibstdc ++ドキュメント C++スタイルのヘッダーは関数のオーバーロードを使用するため、Cスタイルのヘッダー_<c*>_ではなくC++スタイルのヘッダー_<*.h>_を含めることをお勧めします。ヘッダーはそうではありません。

Apple libc ++

_$ clang++ -Wall -Wextra abs2.cc -o abs2
abs2.cc:4:5: error: use of undeclared identifier 'abs'; did you mean 'fabs'?
_

さらに、absの定義を取得するために_<stdlib.h>_も含めると、clang ++はより役立つエラーメッセージを表示します。

_abs2.cc:5:5: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
    abs(1.2);
    ^
abs2.cc:5:5: note: use function 'std::abs' instead
    abs(1.2);
    ^~~
    std::abs
abs2.cc:5:5: note: include the header <cmath> or explicitly provide a declaration for 'std::abs'
abs2.cc:5:9: warning: implicit conversion from 'double' to 'int' changes value from 1.2 to 1 [-Wliteral-conversion]
    abs(1.2);
    ~~~ ^~~
abs2.cc:5:5: warning: ignoring return value of function declared with const attribute [-Wunused-value]
    abs(1.2);
    ^~~ ~~~
_

これは、フロートのオーバーロードが_<cmath>_からのみ利用可能であり、Cの従来のヘッダーからは利用できないことを明示的に示しています。

Apache libstdcxx

インストールしませんでしたが、 math.hヘッダー を調べると、Cの_<cmath>_でも定義されている_<math.h>_の関数がグローバル名前空間に取り込まれますが、 absを含めないでください。

OpenWatcom C++

繰り返しますが、 cmath/math.hヘッダー を調べると、_math.h_として使用すると、absを除いて、Apachelibstdcxxと同じ関数がグローバル名前空間に取り込まれます。

STLPort

math.hヘッダー を調べると、システムのC _<math.h>_ヘッダーが含まれていますが、これはC++ライブラリの一部ではないため、absは含まれていません。 (これはg ++とclang ++が行ったことでもあります。)

Microsoft Visual Studio(Dinkumware)

私自身はこれにアクセスできませんが、 このサイト Visual C++を使用してコンパイルすると主張しており、

_error C4578: 'abs': conversion from 'double' to 'int', possible loss of data
(Did you mean to call 'fabs' or to #include <cmath>?) 
_

それで、文字通りすべての主要なC++標準ライブラリの実装は、この点で標準に違反していますか?

または、標準が_<math.h>_およびその他の従来のCヘッダーについて述べていることを見逃していますか?

15
Nick Matteo

"それぞれがname.hという形式の名前を持つすべてのCヘッダーは、対応するcnameヘッダーによって標準ライブラリ名前空間に配置された各名前が内部に配置されているかのように動作します。グローバル名前空間スコープ。 "

その言い回しは、私には、<cname>ヘッダーのすべての名前がname.hヘッダーに表示されなければならないということではありません。

<name.h>ヘッダー内のすべての名前<cname>内に対応する名前があることを示していますヘッダーはグローバル名前空間に表示される必要があります。

<cname>ヘッダーに表示されない<name.h>ヘッダーの名前については何も述べていません。

C++ 14標準

D.5 C標準ライブラリヘッダー[ depr.c.headers ]

C標準ライブラリおよびCUnicode TRとの互換性のために、C++標準ライブラリは、表に示すように26個のCヘッダーを提供します。

このステートメントでは、「26個のCヘッダー」という用語を使用しており、C++標準が<cname>に含める必要があると言っているものではなく、C標準に含めるべきと言っているものが含まれていることを示しています。

実際、たとえば<cstddef>に関しては、対応するCヘッダーに含まれていないものについて詳しく説明しています。

18.2タイプ[ support.types ]

2内容は標準Cライブラリヘッダー<stddef.h>と同じですが、以下の変更があります。

1
Galik