2013-10-25 22 views
16

私はC++固有のヘッダファイル(例えば<cstdlib>)のみを使用していますが、std名前空間の関数だけでなく、グローバルに宣言された関数も得られます。それを防ぐための方法、おそらくコンパイラスイッチはありますか?std名前空間以外の標準機能の防止

たとえば、次のコード

#include <cstdlib> 
float random() { return 0.0f; } 
int main() { return 0; } 

は、次のエラーで、Linux上でコンパイルに失敗:

> g++ -c main.cpp main.o 
main.cpp: In function ‘float random()’: 
main.cpp:2:14: error: new declaration ‘float random()’ 
/usr/include/stdlib.h:327:17: error: ambiguates old declaration ‘long int random()’ 

又は

> clang++ main.cpp -o main.o 
main.cpp:2:7: error: functions that differ only in their return type cannot be overloaded 
float random() { return 0.0f; } 
/usr/include/stdlib.h:327:17: note: previous declaration is here 
extern long int random (void) __THROW; 

そのstdlib.h "引き起こされます自身のrandom機能でグローバルな名前空間を汚染します。

Visual Studioを使用してWindowsでコンパイルする際に、これらの問題に直面していないことに注意してください。

+1

「ランダム」は、**標準のCライブラリの**一部ではありません。それは問題が本当ではないと言っているわけではありません。 –

+0

@PeteBecker実際、POSIX(http://pubs.opengroup.org/onlinepubs/9699919799/functions/random.html)から来ます。これは、C標準の名前だけでなく、POSIXのすべてのものにも注意する必要があります。 :( –

答えて

10
  1. <cstdlib><stdlib.h>は、常にグローバル・シンボルを定義し、時にはSTD名前空間を移入する一方、常に、std名前空間を取り込み、時にはグローバルシンボルを定義します。これは実装ごとに異なります。

  2. 標準は書いている:コンパイラが同時にでグローバルスコープとstd名前空間にこれらのシンボルを置くことを許可されていることを意味し

    Every C header, each of which has a name of the form name.h , behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope. It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).

    、。

  3. したがって、1つのヘッダーファイルを他のヘッダーファイルよりも優先する利点はありません。 彼らは両方ともグローバルスコープを汚染する可能性が非常に高いためです。

    しかし、まだ時に#include <cstdlib>std名前空間を使用することが必要である、とするとき#include <stdlib.h>あなたのコードは、すべてのコンパイラの実装用にコンパイルできることを確認するために、stdを使用しないでください。

  4. アドバイス標準ライブラリに名前を使用しないでください。第一に、彼らは働くことが保証されていません。 (注:#include <csomething>のときは、実際にはグローバルスコープをきれいにしているコンパイラ実装はほとんどないので、決してこれに依存しないようにしてください。)ほとんどの人が標準名を実際に標準であるとみなすので、コードリーダーとメンテナを混乱させます。 。

+2

ところで、C++ 98では、 ''がグローバルな名前空間を汚染することを許可していないので、多くの実装が要件を満たすことが難しかったため、C++は許可を導入しました(制御しないと、 Cライブラリも同様ですが、私はlibstdC++の人々がこれらの困難を記述している紙を覚えているようですが、今は見つけられません)。 – AProgrammer

6

宣言の衝突を防ぐために、独自の名前空間で関数を宣言できます。

namespace MyFunc 
{ 
float random() { return 0.0f; } 
}; 
+0

私は同意します、それは良いウォークアラウンド、そして良いコーディング慣行で、プロジェクトを別々の名前空間に維持することです。しかし、私はすでに終了しているコードを使ってWindowsから移植しようとしていますLinuxに私は絶対に必要以上に変更したくないと思っています。 – CygnusX1

0

通常、私はあなたの関数名を標準として定義されているものとは異なるものにしたいと考えています。 ここでは、関数名をランダムではなくmyRandomとして使用することで、後で自分のコードを維持する人々に、使用されている関数が標準として定義されているものではないことを知らせることができます。

2

標準では、<c???>ヘッダーがC標準関数の名前をグローバル名前空間に持っていくことを明示的に許可しています。

+3

私の意見では、名前をグローバルな名前空間に入れることは、最初に 'std'名前空間を持つという目的を破ります。 – CygnusX1

+1

理由が何であれ、標準はそれが何をしているのか、そしてその結果、移植可能なコードはC関数と名前の衝突を持たないようにしてください。 –

3

一般に、最初の場所で再宣言を避けるようにしてください。 名前空間を使用するか、ソースをcstdlibなどのファイルに分割し、staticバージョンの(名前の衝突)機能を使用することができます。

これがオプションでない場合は、読んでください。しかし、以下は非常にプラットフォーム固有のものかもしれないことに注意してください。ちょうど私の場所で、ここに私のcstdlibstdlib.h見を有することにより

私はそれがstdlib.hを含むか、または単にstd名前空間のabortatextexitを宣言している場合cstdlibが決定したことにより、スイッチがあることに気づきました。

明らかに、あなたはstdlib.hブランチを引き込みます。このファイルをさらに調べると、__BEGIN_NAMESPACE_STD以降のマクロが__END_NAMESPACE_STDにあることがわかりました。多分あなたはこれを使うことができますが、(名前が示すように)いくつかのインプリメンテーション内部マクロであり、あなたによって直接設定されるべきではありません。しかし、それは何らかの理由でそこにあるはずですので、あなたはそれを探して運があるかもしれません。

さらに検索した結果、random__BEGIN_NAMESPACE_STDにラップされていない関数(および宣言)の1つであることが判明しました。したがって、これは問題の解決策ではありません。 (_GLIBCPP_USE_NAMESPACESというマクロは#define __BEGIN_NAMESPACE_STD namespace std {にも内部的に使われているようです)。

これをまとめます。これは実行可能なパスではなく、上記の回避策のいずれかを使用する必要があります。

+0

Whileマクロ自体は内部的なものかもしれませんが、おそらく、それを有効にするための「パブリック」コンパイラスイッチや別のマクロがありますか? – CygnusX1

+0

私の考えはあまりにも高いですがまだ見つけられませんでした(自分の答えを書くときに検索を始めました)。私はまた、すべてがうまくいけばそれを保証するものではありませんが、一見するとそれは有望でした。 – Nobody