Notice : 内容無保証。禁無断転載。リンク不自由。

main.cpp

// 目標
//   コンパイル時定数 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 では) ちょっと判りやすくなった。