警察だ!(インターネット meme)
以下の正規表現で表される識別子は我々は勝手に使ってはいけません.
処理系に予約されています.コンパイラの内部利用や標準のヘッダ(<algorithm>
とか)で使うためのものです.
.*__.*
_[A-Z].*
_.*
(グローバル名前空間のみ)
正規表現がわからない人向けに例を挙げると,以下のようなものが該当します.
__foo
____foo
f__oo
foo__
_Foo
_foo
(グローバル名前空間のみ)
foo_
などは許されています.
他にも,STL のヘッダを一つでも #include
した場合,いずれかの(すなわち直接 #include
しているかは関係なく)ヘッダで宣言されている名前を #define
するのは未定義([macro.names] に書いてある)です.
それから,keyword と一致するものもだめですね.
なんで予約されてるの
標準ヘッダに書かれているものも当然プログラムなので,変数などを宣言したりしますね. そんなときに,処理系によって変数名がまちまちだったらどうなるでしょう?
#define hello_cplusplus #include <cstdio>
ある環境の <cstdio>
では hello_cplusplus
という変数が使われていて上のコードがエラーになったり,そうでない環境ではコンパイルできたり... というのは困りますね.
逆に,今の処理系でコンパイルできるものが(未定義などを含んでいないにも関わらず)別の処理系でコンパイルできないのはいやですね.
int f() { ... } int f(int x) { ... } int f(double x) { ... }
など同名の関数が定義できるアレです.内部的には,これらはそれぞれ __Z1fv
, __Z1fi
, __Z1fd
のような名前で扱われたりします.
そんなわけで,仕様で規定されている名前を除いて,処理系が自由に使っていい名前と我々が使える名前が分かれています.
逆に,我々が勝手に使えるはずの名前を #define
するとこわれる処理系は不適格とされるはずです.
いつもの
さて,これらの識別子を勝手に使った場合の動作は未定義なんですよね. 少し遊んでみましょうか.
#define _STDIO_H #define _STDIO_H_ #define __STDIO_H // 念のためいろいろやっておく #include <cstdio> int main() { puts("Hello"); }
どうですか? たくさんエラーメッセージが出てきませんか? インクルードガードと衝突するためですね.
#define c #include <queue> int main() {}
これもだめでしょう.は?って感じですね.
std::queue
のメンバ変数に c
という名前が存在することが規定されています.
これどうにかならなかったんですかね.
#define int long long
実は未定義っぽいというアレ.
(GCC だと大丈夫と 文書化 されているので大丈夫な気もします)
この記事にもありますが,ちゃんと動いてそうに見えても未定義は未定義です.何が起きても知らないですからね.
int _Z1fv = 0; int f() { return 42; }
invalid symbol redefinition とか出てくる.事情を知らないと意味不明そう.
例
ところで,我々が普段目にするもので,この予約された名前がいくつかありますね?
__builtin_popcount
__builtin_*
系の関数です.GCC の組み込み関数たちですね.
知らないものもたくさんあるでしょう?
ちゃんと文書化されていますし,GCC を前提とするなら使っても問題ないでしょう.
std::__gcd
闇の競プロ er がよく使っていますね.
これは,<algorithm>
の中で rotate
の実装のために用意されたヘルパ関数であるみたいなことがコメントで書かれています.なんですが,使われていなさそう? わからない.
文書化されておらず,内部利用のためのものなので,積極的には使わない方がいいのでは?と思っています.
std::bitset::_Find_next
std::bitset<128> bs; bs._Find_next(n);
などとすると n
以降に on になっているビットの添字を見つけてくれるやつです.
これも文書化されてないようなので,...
や,文書化されているかどうかがそこまで大事かは人によりそうですけど. 消えたり仕様が変わったりしないのかなとか,えびちゃん的には気になっちゃう.
_GLIBCXX_DEBUG
デバッグに役立ちそうなやつ.
#define _GLIBCXX_DEBUG #include <vector> int main() { std::vector<int> v(2); v[100]; // error }
文書化されてると安心しちゃう.
_USE_MATH_DEFINES
ここが詳しい.
要するに,これを #define
した場合の動作は未定義なので,我々が勝手に使えるはずの M_PI
などの名前を処理系が勝手に提供してもコンパイラは怒られないという話.
パトロール
処理系のコードをコピペしてきたのか知らないですけど,こういうテンプレを書いていませんか?
template <typename _Tp> ostream& operator <<(ostream& os, _Tp const& x) { ... return os; }
_Tp
は取り締まり対象なんですよね.
まとめ
あえて予約された名前を宣言するメリットはないはずなので,避けませんかという話でした. それが原因で意味不明なエラーと戦いたい人は,すきにしたらいいと思います...?
処理系の独自機能であるようなものは,大抵は名前でわかる(_Exit
など例外あり)ので,使う際にはどの程度の可搬性があるか考えてみるとよさそう?