まず、いくつかの用語:
- using-declaration:
using std::vector;
- using-directive:
using namespace std;
ヘッダーファイルのグローバルスコープで使用されていない限り、usingディレクティブの使用は問題ないと思います。だから
using namespace std;
.cppファイル内の問題は実際には問題ではありません。問題が発生した場合は、完全に管理下にあります(必要に応じて、特定のブロックにスコープを設定することもできます)。多数のstd::
修飾子を使用してコードを乱雑にする特別な理由はありません。それは単なる視覚的なノイズになります。ただし、std
コードで名前空間からの名前の集まり全体を使用していない場合は、ディレクティブを省略しても問題はありません。これはトートロジーです-ディレクティブが必要なければ、それを使用する必要はありません。
同様に、名前空間の特定の型に対して(using-directivesの代わりに)いくつかのusing宣言で問題が解決しない場合は、特定の名前だけを現在の名前空間に持ち込むべきではない理由はありません。同じように、1つのusingディレクティブでもうまくいく場合は、25か30のusing宣言を行うのはおかしく、簿記は面倒だと思います。std
また、using宣言を使用する必要がある場合があることも覚えておくとよいでしょう。スコットマイヤーズの「Effective C ++、Third Edition」の「Item 25:Non-throwing swap for support for a non-throw swap」を参照してください。テンプレート化された汎用的な関数でパラメーター化された型に「最良の」スワップメソッドを使用するには、使用宣言と引数に依存するルックアップ(ADLまたはKoenigルックアップとも呼ばれます)を利用する必要があります。
template< typename T >
void foo( T& x, T& y)
{
using std::swap; // makes std::swap available in this function
// do stuff...
swap( x, y); // will use a T-specific swap() if it exists,
// otherwise will use std::swap<T>()
// ...
}
名前空間を大幅に使用するさまざまな言語の一般的なイディオムを検討する必要があると思います。たとえば、JavaとC#はネームスペースをかなりの範囲で使用しています(おそらくC ++よりも多く)。これらの言語で名前空間内の名前を使用する最も一般的な方法は、usingディレクティブと同等の機能を使用して、それらをまとめて現在のスコープに入れることです。これは広範囲にわたる問題を引き起こさず、問題であることがまれに、完全修飾名を介して問題の名前を処理することによって、またはC ++で行うことができるのと同じようにエイリアスを使用して、「例外」ベースで処理されます。
Herb SutterとAndrei Alexandrescuは、彼らの本、C ++ Coding Standards:101 Rules、Guidelines、and Best Practicesの「Item 59:Do n't write namespace usings in a header file or before the #include before」をこのように述べています。
つまり、宣言の後の実装ファイルで宣言とディレクティブを自由に使用して名前空間を使用できます#include
。反対の主張が繰り返されているにもかかわらず、宣言とディレクティブを使用した名前空間は悪ではなく、名前空間の目的を損なうことはありません。むしろ、それらは名前空間を使用可能にするものです。
Stroupstrupは、「C ++プログラミング言語、第3版」で、「グローバル名前空間を汚染しないでください」とよく言われます。彼は実際にそれを言う(C.14 [15])が、C.10.1の章を参照して彼はこう言っている:
using宣言はローカルスコープに名前を追加します。使用して、ディレクティブはありません。宣言されたスコープでアクセス可能な名前をレンダリングするだけです。例えば:
namespaceX {
int i , j , k ;
}
int k ;
void f1()
{
int i = 0 ;
using namespaceX ; // make names from X accessible
i++; // local i
j++; // X::j
k++; // error: X::k or global k ?
::k ++; // the global k
X::k ++; // X’s k
}
void f2()
{
int i = 0 ;
using X::i ; // error: i declared twice in f2()
using X::j ;
using X::k ; // hides global k
i++;
j++; // X::j
k++; // X::k
}
ローカルで宣言された名前(通常の宣言またはusing宣言のいずれかで宣言)は、同じ名前の非ローカル宣言を非表示にし、名前の不正なオーバーロードは宣言の時点で検出されます。
以下のための曖昧エラーに注意してくださいk++
では
f1()
。グローバル名は、グローバルスコープでアクセス可能にされた名前空間の名前よりも優先されません。これは、偶発的な名前の衝突に対する重要な保護を提供し、さらに重要なことには、グローバル名前空間を汚染することから得られる利点がないことを保証します。
多くの名前を宣言するライブラリがusingディレクティブを介してアクセス可能になる場合、未使用の名前の衝突がエラーと見なされないことは大きな利点です。
...
名前空間を使用する新しいプログラムでは、従来のCおよびC ++プログラムと比較して、グローバル名の使用が大幅に減少することを期待しています。名前空間の規則は、グローバルスコープを汚染しないように注意する誰かよりもグローバル名の「怠惰な」ユーザーに利点を与えないように特別に作成されました。
そして、どのように「グローバル名の怠惰なユーザー」と同じ利点を持っていますか?名前空間の名前を現在のスコープで安全に使用できるようにするusingディレクティブを利用する。
違いがあることに注意してくださいstd
。usingディレクティブを適切に使用してスコープで使用できるようにされた名前空間の名前(ディレクティブをの後ろに配置することにより#includes
)は、グローバル名前空間を汚染しません。それらの名前を簡単に利用できるようにするだけであり、衝突に対する継続的な保護を備えています。