usingディレクティブ
using namespace 名前空間名;
による記述は usingディレクティブ(using directive)と呼ばれます。特定のスコープ内でusingディレクティブが記述されると、以降のスコープ内では名前検索の範囲が指定された名前空間内にまで拡張されるような挙動を取ります。
例えば、C++標準ライブラリの名前空間名であるstd
がusingディレクティブに指定された場合、同空間内のメンバであるstd::cout
オブジェクトやstd::string
クラス、std::max
関数等が、std::
による名前修飾無しに利用できるようになります。
#include <iostream> // std::cout
#include <algorithm> // std::max
#include <string> // std::string
int main() {
using namespace std;
cout << string("abc", 0, max(1, 2));
// 以下と同等の記述
std::cout << std::string("abc", 0, std::max(1, 2));
}
なお、usingディレクティブは名前空間内や関数スコープ、その他のスコープ内でも利用できますが、クラススコープでは利用できないという特徴があります。
struct T {
using namespace std; // error: 'using namespace' is not allowed in classes
};
目次
- usingディレクティブの注意点
- using宣言(メンバを個別に取り込みたい場合にオススメ)
- using宣言とusingディレクティブの違い
usingディレクティブの注意点
usingディレクティブは基本的に、グローバルスコープ内、とりわけヘッダファイル内では利用しないようにし、仮にファイルスコープ内や個別の名前空間内で扱う場合であっても、名前衝突等の問題が起こらないことが明確な場合にのみ慎重に扱うようにすることをオススメします。
usingディレクティブの多用は、名前空間の汚染や機能名の競合、標準型とユーザ定義型の区別が曖昧になる問題など、様々な問題を引き起こす要因となるため注意して扱う必要があります。
このusingディレクティブの利用によって生じる様々な問題については、以下の記事でusing namespace std;
の記述を例に詳細に解説されているため、参考にしてください。
using namespace std; の危険性と注意点・代替案
using宣言
usingディレクティブと似たような機能にusing宣言というものがあります。
こちらは名前空間全体ではなく、名前空間内の個別のメンバ名を取り込む機能となっています。
void f() {
using std::string;
string s = "hello"; // `std::`の省略が可能に
}
例によってクラススコープでの宣言は行なえません。この場合はエイリアス宣言(using 識別子 = 型名
)を用いて別名を宣言するとよいでしょう。
struct T {
using std::string; // error: Using declaration in class refers into 'std::', which is not a class
using string = std::string; // OK
};
using宣言とusingディレクティブの違い
using宣言は、指定された型をusing宣言された領域に追加するような挙動をとります。そのため、既存の型名と同名の型名を再宣言した場合には、using宣言で再宣言された方の型が、より局所的な型として優先的に利用されることになります。
struct string {};
void f() {
string s; // 変数`s`は`struct string`型
using std::string;
string t; // 変数`t`は`std::string`型
}
逆にusingディレクティブは宣言ではないため、あくまで指定された名前空間内のメンバを名前探索の範囲に含めるような挙動をとります。そのため、usingディレクティブによって注入されたメンバ名と、既に宣言されている既存の型名が重複する恐れがあります。
struct string {};
void g() {
string s; // 変数`s`は`struct string`型
using namespace std;
string s; // error: reference to 'string' is ambiguous
// `struct string`型と`std::string`型のどちらを用いればいいのかが曖昧
}
このように、usingディレクティブを記述した段階では名前衝突は発生しませんが、重複した識別子を利用した段階では曖昧な名前解決が発生するため、エラーに繋がります。