// 目標 // コンパイル時定数 exp が、 // 0 のとき : コンパイルエラー // 0 以外のとき : 実行時コスト0 (= コンパイル後のコードに現れない) // ような、StaticAssert(exp) を作る。 // [追加条件] // exp が コンパイル時に決まらない変数の場合もコンパイルエラーとなること。 // コンパイルが通るとき、余計な warning が出ないこと。 // エラーメッセージがもうちょっと判りやすくなるように工夫できないか。 // warning「ローカル変数は 1 度も使われません」を出さないためには、 // 型だけが必要な状況を作ってやれば良い。 // たとえば、 // struct S {} ; // (void)sizeof(S) ; // のようにすれば、S の インスタンスを作る必要は無い。 // 後は、exp が 0 のときに、上記の S が未定義となるように出来れば、 // (void)sizeof(S) ; でコンパイルエラーが出せる。 // コンパイル時の定数に応じて新しい型を作りだすにはテンプレートが使えそうである。 // そこで、exp に 0 が指定されたとき、テンプレートが未定義となるように細工してみる。 template <bool> struct CstaticAssert ; template <> struct CstaticAssert<true> {} ; // CstaticAssert テンプレートの true バージョン // template <> struct CstaticAssert<false> {} ; // false バージョンはわざと未定義にしてやる #define StaticAssert(exp) (void)sizeof(CstaticAssert<(exp) != 0>) int main(void){ StaticAssert(1) ; // コンパイルを通ること StaticAssert(2) ; // コンパイルを通ること StaticAssert(0) ; // コンパイルエラーとなること int i = 1 ; StaticAssert(i) ; // コンパイルエラーとなること return 0 ; } // これでコンパイルが通るときの warning は出なくなり、 // エラーメッセージにも、「認識できない型 'CstaticAssert<0>' が使われています。」 // と、テンプレート名が表示され (VC++6.0 では) ちょっと判りやすくなった。