見出し画像

C++ 再入門 その3 名前空間の罠

前回、次は「名前空間」をやりますと書いたのですが、唐突でこれが何を意味するのかわからない人もいるでしょう。C言語教室でも構造体宣言のところなどで名前空間という単語が出てきたかもしれませんが、関数名や変数名などの識別子がどのグループに含まれるのかという話です。

C言語の例をとると構造体変数の宣言の際には必ず struct と書くので、型の名前と変数の名前の区別が付くので、同じ名前を付けても大丈夫なのは、この名前空間が異なるからです。文法的にどちらの名前空間の名前が登場するかがわかればコンパイラとしては何も困りません(人間が混同することはありますけど)。もっともCと異なりC++ではstructの名前空間の扱いが少し違うので、要注意なんですが、それはいずれ取り上げます。

名前空間

いずれのせよグローバルな名前空間にある変数名であるとか関数名は同じ名前空間にあるので、これらの名前がかち合うとコンパイルできなくなってしまうわけです。これがライブラリとして使う関数に対して起こってしまうと困るわけで、自分で適当につけた関数名が他のライブラリで使っていたりするとアウトな訳です。自分で作ったのであれば変えることも出来るのですが、複数のライブラリの間で同じ名前の関数があれば、もうそれらを両方とも使うことは出来ません。

一般的にはライブラリで使うような関数の名前はライブラリ全体で共通する名前から始まるように作ることが多いのは、そうすれば名前が被りにくいという事情もあるわけです。例えば文字列処理は str であるとか mem で始まるのは、機能が予想しやすくインクルードするファイルを忘れにくいという効果もあるのですが、多くのコードや他のライブラリからも呼び出されるので、名前がぶつからないようにする役割もあります。

業務で作るプログラムでは、名前が被らないように会社名やプロダクト名を名前の最初に付けるということが良く行われます。そうしないと他の関数と名前が被ることが起こりかねませんし、トラブルが起こった際に、その責任の所在がわかりやすくなるという理由もあります。

こんな苦労があるので、20世紀最後の方からは多くのプログラミング言語で名前空間という仕組みが導入されました。ひとつひとつの名前に識別子を付けるのではなく、ヘッダファイルなどで関数名や変数名などを namespace で囲ってひとまとめに識別子をつけてしまうのです。

例えば入出力で使う関数などは iostream の中で、namespace std という名前空間で括っています。ですので、このヘッダで定義された名前を使うときには、必ず std:: と名前空間の名前と2つのコロンを最初につけて使うのです。そのため cout であるとか endl という名前は、std名前空間にある名前なので、

#include <iostream>
void main() {
  std::cout << “Hello World!\n” << std::endl;
}

と書かなければなりません。分かりやすいかもしれませんが、ちょっと面倒ですね。そこで、これらを頻繁に使うのであれば、使う方のコードで using を使い、宣言した名前空間は省略してしまうのです。

#include <iostream>
using namespace std;
void main() {
  cout << “Hello World!\n” << endl;
}

Visual Studio などの IDE では、ウィザードにコードを書かせると using を使わずに、stdを付けたコードを出してくるのですが、一般的に自分の書くコードに関しては using を使ってしまったほうがstdを忘れてエラーになることを防げますし、デバッグなどの目的でstdをラップすることもあり得るので、特別な理由がなければ using を使ったほうが良いでしょう。

ということで教室では理由がない限り using を使うことにします。まあ iostream をインクルードしたら、using namespace std と書いてstdは忘れるんだとだけ覚えていれば良いでしょう。

名前空間 (C++)

というところで次は演算子に進みますか。


さて、これだけだと既にC++に詳しい人には物足りないと思うので、少し余談を書いておきます。

名前空間のポイントとしては、入れ子に出来ることと、inlineという限定usingがあります。そして名前解決の際に、どの順序でどの空間の識別子が検索されるのか、ここで同じ名前があるときに何が起こるのかが実にややこしいのです。またヘッダファイルとソースファイルでnamespaceの括り方が異なることもあるので、これを一致させないと正しくプロトタイプ宣言が出来ません。ヘッダファイルで using を使うとロクなことにならないので、キチンと書こうとするのですが、関数名だけではなく型名などもすべて名前空間を書く必要があるので、結構、凄いことになりがちです。テンプレートも名前空間を持つので、ちょっと人の目で追いきらない事態もありますね。

標準C++ namespaceについて

C++名前空間

インライン名前空間定義 (C++11)

なぜusing namespace std;を避けるべきか

この辺りは最近の流儀を調べているところなので、そのうち挑戦しましょう。

#cpp #プログラミング講座 #namespace #using #std


この記事が気に入ったらサポートをしてみませんか?