コンパイル時チェック (STATIC_CHECK)

template で定義してるんだけど wchar_t の対応をまだ考えてないクラスが多くなってきたので,そう言ったクラスはいっそ char 以外で使われたらコンパイル時にエラーメッセージを出してしまうようにしようと STATIC_CHECK を実装してみました.しかし,Modern C++ Design に掲載されている実装だと(期待しない別の)コンパイルエラーが発生してしまうようです(gcc 3.4.4, and 4.3.2. ともに cygwin).

解決方法を Web で調べてたところ,http://www.rhinocerus.net/forum/language-c-moderated/563180-modern-c-design-compiletimechecker-issue.html で紹介されている方法が良さそうだったので,これを採用しました.ただし,紹介されている方法のままだと unused variable と言う warning が出るので若干修正.

template <bool> struct compile_time_checker;
template <> struct compile_time_checker<true> {
    void check_done() {}
};

#define STATIC_CHECK(expr, msg)                 \
    if (false) {                                \
        compile_time_checker<(expr) != 0>       \
        error_##msg;                            \
        (error_##msg).check_done();             \
    }

msg で指定された名前で compile_time_checker 型の変数を定義するためのマクロなのですが,compile_time_checker は実装が定義されていないのでコンパイルエラーとなります.これを利用して STATIC_CHECK の expr が偽のときにコンパイルエラーを出しています.if (false) の部分は,if(false)を追加したほうがコンパイラには最適化しやすいようです と言う指摘があったので,何となく従ってみました.

int main(int argc, char* argv[]) {
    /*
     * STATIC_CHECK マクロは,第 1 の式が false になるときに,
     * error_##msg と言うコンパイルエラーを表示させるためのマクロ.
     */
    STATIC_CHECK(sizeof(char) == 1, static_check_is_ok);
    STATIC_CHECK(sizeof(int) == 1, print_static_check_message);
    STATIC_CHECK(sizeof(char) == 1, static_check_is_ok);
    
    return 0;
}
gcc 3.4.4 (cygwin)
$ g++ -I.. -Wall example_static_check.cpp 
example_static_check.cpp: In function `int main(int, char**)':
example_static_check.cpp:43: error: aggregate `compile_time_checker< false>
error_print_static_check_message' has incomplete type and cannot be defined
gcc 4.3.2 (cygwin)
$ g++-4 -I.. -Wall example_static_check.cpp 
example_static_check.cpp: In function 'int main(int, char**)':
example_static_check.cpp:43: error: aggregate 'compile_time_checker<false>
error_print_static_check_message' has incomplete type and cannot be defined

"error_print_static_check_message" が伝えたいエラー内容を出力する部分です.コンパイルエラー時に出力されるメッセージが期待された通りのものかどうかはコンパイラ次第なのですが,gccVC++ ではそれっぽい(エラーとなった理由が分かる)エラーメッセージが出力されるようです.