しのはらのC++実験室トップページ
「移植性の高いプログラムの書き方」トップページ
for(int i=0; i<10; ++i ){
/* .... */
}
これは「変数は使う場所で宣言」というC++の考え方を実践している文法と言えます。
また、ここで宣言しているint
型変数i
のスコープ(つまり有効範囲)はforループ内部に限定されています。
forを抜けたあとではi
を使うことはできません。
これがC++の仕様です。
このように、i
はまさにforループのための変数なので、
forループが始まると同時に必要となり、
forループが終わったあとでは必要のないものとなるという意味論を
反映した合理的な仕様であるといえます。
i
の二重定義エラーになっていました。
for(int i=0; i<10; ++i ){
/* .... */
}
/* .... */
for(int i=0; i<10; ++i ){
/* .... */
}
この事実は、古いC++の仕様に基づくコンパイラとそうでないコンパイラの間で
コードを移植する際に問題となります。
int i;
for(i=0; i<10; ++i ){
/* .... */
}
/* .... */
for(i=0; i<10; ++i ){
/* .... */
}
この方法では「変数は使う場所で宣言」という、
コードを読みやすくするための経験的ルールに反します。
またループの外部でもループ変数が生きているため、
誤ってループ外部で使用してしまう間違いをコンパイラに指摘させることができません。
#define for if(0);else for
このように定義されたforを使用すれば、ループ変数のスコープに関してコンパイラがどちらの意味論に従っているかに関係なく、同じ結果を得ることが出来ます。
しかもそれは古くないC++の仕様に従うものです。
つまりこのマクロ定義を使えば、安心して最新仕様に基づくループ変数を使用できるようになるのです。
#define for if(1)for
これだとfor文の直後にelseが来る場合に、間違ったコードを生成します。
そこで僕は最初、次のように修正しました。
#define for switch(0)default:for
これは期待通りに機能します。しかしコードの質にこだわる人にとって少しだけ問題がありました。一部のコンパイラではこのような明らかに無用かつ無害な構文のためにさえ若干の無駄なコードを生成してしまうのです。
すなわちswitch構文を使用することによるコストが生じてしまうのです。if(0);else
という、switchに比べてより複雑さの少ない方法を使用することで、解決できました。