BOOST_STATIC_ASSERT(exp)

#include <boost/static_assert.hpp>

#include <boost/type_traits/is_void.hpp>

template<typename T>
struct type_size{
    BOOST_STATIC_ASSERT(!boost::is_void<T>::value);    // void 以外を受け付ける
    static const int value = sizeof(T);
};

int
main(){
    
    BOOST_STATIC_ASSERT(sizeof(int) == 4);
    BOOST_STATIC_ASSERT(sizeof(short) == 4);    // コンパイルエラー
    
    type_size<int>::value;
    type_size<void>::value;     // void なのでエラー

    return 0;
}


assert() が、実行時にエラーを検知するのに対し、BOOST_STATIC_ASSERT() は、コンパイル時にエラーを検知する機構です。
assert() と同じで、false が渡されるとコンパイルエラーになります。
BOOST_STATIC_ASSERT() は、typedef が出来る場所であればどこでも使用可能かな?


また、コンパイル時に式を展開するので、変数の値を渡すことは出来ません。

int value;
BOOST_STATIC_ASSERT(value < 10);    // value は動的変数なので比較出来ない

static const int static_value = 255;
BOOST_STATIC_ASSERT(static_value > 10);    // static_value は、定数式なので OK


あと地味にはまったのがこのエラー。

template<typename T>
void
hogehoge(){
    BOOST_STATIC_ASSERT(!boost::is_same<T, void>::value);
    // is_same は、渡される型が同じなら true を返す
}

hogehoge<int>();


template 引数型が、void の時にエラーを出すように処理しているのですが、なぜかコンパイルエラーになります。
これは、BOOST_STATIC_ASSERT() を展開する時に、

// <> は比較演算子として処理されている!?
BOOST_STATIC_ASSERT( (!boost::is_same<T), (void>::value) );

の様に、意図しない場所で区切られてしまうからである。
言われてみると納得するが、実際にエラーが出ると全然気づかなかった…。

// () でくくって回避
BOOST_STATIC_ASSERT(( !boost::is_same<T, void>::value ));


このような感じで、template を使用する場合の型を制限したり、定数を確認したり出来ます。
静的に配列へアクセスを行う際にサイズオーバーをしてないかの確認や、memcpy を行う際に型のサイズをチェックしたりとやれる事は地味に多いかな?
まぁ、template の型制限に限って言えば、concept があれば、うわなにをするやめ(ry。
ちなみに、assert() とは違い、リリースビルドでも検知を行ないます。


[boost]
ver 1.44.0