もうすでにN人がN回言ってる有名な話なのですが改めて。
結論
よく分からないならusing namespace std;
を使わない
あとこれは難しいかもしれませんが、エラーの中から英語っぽいのを探して検索を掛けましょう。ほぼ100%解決策が出てきます。
— Az (@azaika_) 2017年4月23日
あと「よく分からないなら using namespace std; を使わない」は100回くらい復唱しましょう
using namespace std;
とは
#include <iostream> int main() { std::cout << "arikitari_na_sekai" << std::endl; }
こういうコードでstd::
を書きたくないというときに
#include <iostream> using namespace std; int main() { cout << "arikitari_na_sekai" << endl; }
と書くことです。
太古の昔のC++には名前空間がなかった
はい、昔はなかったんです。どれくらい昔かというと、#include <iostream>
ではなく#include <iostream.h>
と書いていた時代ですね。
そのせいもあってか、名前空間を標準ライブラリ(STL)はすべてstd
名前空間に
圧倒的魔界なC++の名前探索
関数に限っても、まず名前空間があり、ADL(実引数依存探索)があり、そのためのunqualified name look-upがあり、これにtemplateが加わって、さらに関数オーバーロードの複雑極まる規則が、とぱっと浮かぶ単語を並べるだけでも魔界です。
この仕様を把握しきれている人いるんですかねぇ(自分は無理)
競技プログラミング界隈での利用
競技プログラミング界隈は
- 短く書く
- シンプルで問題の制約上不要なエラーハンドリングは省く
- 実行速度を速く
- コード記述速度も速く
を求める世界です、少なくとも私にはそう見えます。
「短く書く」「コード記述速度も速く」の実現のために、using namespace std;
が利用されることが多いです。
using namespace
が事実上必須な場面
例えばC++14で追加された、標準ライブラリでのUDLsの利用では
#include <string> void foo(const std::string& s) { //do something } int main(int argc, char* argv[]) { foo(std::string("argv[0]:") + argv[0]); }
と書く代わりに
#include <string> void foo([[maybe_unused]] const std::string& s) { //do something } int main(int, char* argv[]) { using namespace std::literals; foo("argv[0]:"s + argv[0]); }
のように書けます。もちろんusing namespace
を使わずに
#include <string> void foo([[maybe_unused]] const std::string& s) { //do something } int main(int, char* argv[]) { using std::literals::string_literals::operator""s; foo("argv[0]:"s + argv[0]); }
のようにusing
で引っ張ってくることも出来ますが、あまりに面倒すぎるので、この場合using namespace
は事実上必須と言えますね。
問題点
名前が衝突してコンパイルが通らない
名前が衝突してかつ一意に定まらないとコンパイルエラーになります。
最も身近なのは、C++17でgcd()
, lcm()
が標準入りしたのですが、自前でそれを実装している人でしょうかね。
知らぬ間にC++17になっていたコンテストでusing namespace stdしたうえでgcdとlcmを自分で定義して死んで欲しい
— Az (@azaika_) 2016年9月15日
あとは @tancahn2380氏の
# include <iostream> # include <vector> # include <limits> # include <algorithm> # include <map> # include <string> # include <functional> # include <cmath> # include <iomanip> using namespace std; int main() { string a, b, c; cin >> a >> b >> c; transform(a.begin(), a.end(), a.begin(), toupper); transform(b.begin(), b.end(), b.begin(), toupper); transform(c.begin(), c.end(), c.begin(), toupper); cout << a[0] <<b[0] << c[0] << endl; }
https://abc059.contest.atcoder.jp/submissions/1239801
とかでしょうか。
偶然名前解決に成功して全く違う処理が呼ばれる
コンパイルでコケル分には何もダメージがないから良いんですよ。知らぬ間に全く違う動作をする別の関数に飛ばされて、しかも偶然ユニークに名前解決が出来てしまって、動作がおかしくなるって言う、そういうかなりのレアケース引かないといけなくて。
— Hideyuki Tanaka (@tanakh) 2016年9月15日
可読性
複数のライブラリを使うときに、どの関数がどの名前空間にあるかわからないと、正しい関数を呼び出せているかわかりにくくなります。
using namespace
によって名前空間が省略されていると、それができないんですね。
いや、IntelliSenseあるだろという声が聞こえそうですが、いちいちマウスかざしてられっか!
一方で
#include <chrono> #include <iostream> void foo(){} int main() { const auto t1 = std::chrono::high_resolution_clock::now(); foo(); const auto t2 = std::chrono::high_resolution_clock::now(); std::cout << std::chrono::duration_cast<std::chrono::miliseconds>(t2 - t1).cout() << std::endl; }
のように名前空間が深いと辛いので
#include <chrono> #include <iostream> void foo(){} int main() { namespace ch = std::chrono; using clock = ch::high_resolution_clock; const auto t1 = clock::now(); foo(); const auto t2 = clock::now(); std::cout << ch::duration_cast<ch::miliseconds>(t2 - t1).cout() << std::endl; }
とかしてあげるといいと思います。
多分すべてのC++erが同意できるusing namespace std;
を書いてはいけない場所
ヘッダーファイルのグローバル名前空間にて。
そのヘッダがincludeされるすべての翻訳単位にusing namespace std;
を書くのと同じことなので(#include
はただの自動コピペマシーン)、イスラム教徒に豚肉を食べさせる並のテロです(自分はイスラム教徒ではないので実際のところは知らず)
競技プログラミング界隈の人とそれ以外の人でusing namespace std;
を書いていいか揉める場所
ヘッダーファイル以外のグローバル名前空間にて。
つまり冒頭の
#include <iostream> using namespace std; int main() { cout << "arikitari_na_sekai" << endl; }
これ。
比較的多くのC++erが同意できるusing namespace std;
を書いていい場所
関数の中。
つまり
#include <iostream> int main() { using namespace std; cout << "arikitari_na_sekai" << endl; }
これ。
自分は可読性の観点からこれも避けたい過激派です。
なぜ競技プログラミング界隈の人とそれ以外のC++erが揉めるか
競技プログラミング界隈の人の主張
- 何が悪いのかわからない
- 名前衝突とかなったことない
- 短くかけるのは正義
それ以外のC++erの主張
- 名前衝突したことないとか一つのプログラムあたりの長さが短すぎるだけだろ
- そもそも競技プログラミング界隈の人はクラス書いて継承したりとかファイル分割の仕方とかヘッダファイルの存在とか名前空間の概念とか理解してない人の方が多いんじゃないか
- 一回書いたコードをメンテナンスしてみてから言いやがれ
- 複数人開発してから出直して、どうぞ
個人的な思い
競技プログラミングでヘッダーファイル以外のグローバル名前空間にてusing namespace std;
するのはまあ許せる
理由:
- 競技プログラミングの哲学もわかる
- 複数ファイルに別れることはない
- 何百行に渡ることは少ない
- メンテナンスしない
- 複数人開発しない
競技プログラミング界隈の文化をよそに持ち込まないでくれ
競技プログラミングとそれ以外では何のためにコードを書くかからして違うわけで、何が最適かも変わるわけです。
つまり文化が違うわけで、文化の多様性を考慮するべきなんですね
競技プログラミングでもしないほうがいい
上に書いたように
# include <iostream> # include <vector> # include <limits> # include <algorithm> # include <map> # include <string> # include <functional> # include <cmath> # include <iomanip> using namespace std; int main() { string a, b, c; cin >> a >> b >> c; transform(a.begin(), a.end(), a.begin(), toupper); transform(b.begin(), b.end(), b.begin(), toupper); transform(c.begin(), c.end(), c.begin(), toupper); cout << a[0] <<b[0] << c[0] << endl; }
のように死んでしまうので、自力で調べて解決できない人はやらないほうがいいと思います。
解決策
C++標準化委員会がmoduleを標準入りさせる
workaround
競技プログラミングとそれ以外の世界は別物なのでそれをわかった上でプログラミングする
閑話休題
ヘッダー名が
— yumetodo-レポート辛い (@yumetodo) December 15, 2017
using_namespace_std.h
で中身が
using namespace std;
という恐ろしいファイルの目撃証言を @kagucho_kamioda から得てしまった・・・
(つд⊂)ゴシゴシ
・・・えっ