std::cout
やstd::string
等の省略記法(cout
, string
)をusing namespace stdを用いずに個別に利用可能にする方法を紹介します。型指定が可能なstd::vector
やstd::map
等のテンプレート・クラスも個別に宣言できます。
ちなみにusingディレクティブを用いてusing namespace std;
と記述すれば、std内の全てのメンバの省略記法が一括で利用可能になりますが、若干危険であるため(参考:usingディレクティブ|using namespace std; の危険性と注意点・代替案)、今回個別に宣言する方法を紹介したいと思った次第です。
目次
- using宣言(変数や関数、クラスを個別に取り込みたい場合)
- エイリアス宣言(型指定済みのテンプレートクラスに別名を付けたい場合)
- エイリアステンプレート(型指定が可能なテンプレートクラスを再定義したい場合)
- usingの活用方法について
using宣言
using宣言(using declaration)によって、特定のメンバのみを取り込むことができます。クラススコープ以外の一般的なスコープで宣言が可能です。
using std::cout;
using std::endl;
// Before
std::cout << 123 << std::endl;
// After
cout << 123 << endl;
関数の場合も同じ記法を用います
using std::max;
using std::sort;
using std::move;
std::string
クラスの場合も変数の時と同様の記法が使えます。
using std::string;
エイリアス宣言
std::vector<std::string>
等のテンプレートクラスの場合にはエイリアス宣言(alias declaration)による別名での宣言が必要となります。
using String = std::string; // 別名も付けられる
using strings = std::vector<std::string>;
strings v = {"A", String("B")};
エイリアステンプレート
エイリアステンプレート(alias templates)により、型指定が必要なテンプレートクラス(std::array<T>
, unique_ptr<T>
等)を別名で定義することも可能です。
template<typename T>
using vector = std::vector<T>;
vector<int> v = {1, 2, 3};
usingの活用方法について
これらのusing宣言/エイリアス宣言/エイリアステンプレートによる個別の宣言/定義をどのタイミングで行うべきかに関してですが、using namespace stdの代替として使うのであれば、ファイルスコープへの汚染を慎重に考慮した上で、従来どおりmain関数の外や実装ファイルの冒頭で利用するのもよいかと思います。
ただし、一番のオススメは必要になった時に局所的に定義する方法です。特に頻繁に使われないようなクラスではこちらの方法がベストです。
namespace mylib {
// 名前空間で個別に宣言(mylib内限定で利用可能)
using std::cout;
void test() {
// 関数内で個別に宣言
using std::endl;
cout << 1 << endl;
cout << 2 << endl;
}
struct String {
// クラス内で個別に定義
using string = std::string;
string _str;
String(const char* str) : _str(str) {}
void print() { cout << _str << std::endl; }
};
// 無名名前空間だと同一名前空間に汚染するので注意
namespace { using std::endl; }
// 侵食したendlが使えてしまう
void hazard() { std::cout << endl; }
}