第4回はstatic_assertです。(正直もっと後で良かった気もする)
まずは以下のプログラムを見てください。
1: #include <string> 2: 3: using namespace std; 4: 5: //テンプレートを使用した2次元上の点の構造体 6: template<typename T> 7: struct Point 8: { 9: T x, y; 10: }; 11: 12: int main() 13: { 14: //数値を扱う型で生成 15: Point<int> pos1; 16: Point<float> pos2; 17: 18: //文字を扱う型で生成(座標を文字で・・・?) 19: Point<char*> pos3; 20: Point<string> pos4; 21: 22: return 0; 23: }
構造体を利用する時に、複数の型で生成できるようにテンプレートを使用するということはよくあります。
ただ18行目から先を見ると分かるのですが、やろうと思えば文字列を扱う型で生成なんてことが出来てしまいます。
安全性の考慮や本来の目的以外で使わせたくない、そういうときはどうすればよいでしょうか?
・頑張ってassertを使う場合
1: template<typename T> 2: struct Point 3: { 4: T x, y; 5: Point() 6: { 7: assert(sizeof(x) != sizeof(char*)); 8: assert(sizeof(x) != sizeof(string)); 9: } 10: };
assertでやったことがないのでよく分からないですが、多分こんな感じになります。
一応これでchar*とstringを検出したら警告が出ます。
ただ、この方法の問題として
・他の型も警告に追加する時記述を増やす必要がある
・char*やstringと同じサイズの他の型でも警告がでる(というよりポインタのサイズが4なので、int型で警告出ます)
・警告が出るのは実行した時
等があり、あまり実用的ではありません。
では次に、C++11で追加されたstatic_assertを使用してみましょう。
1: template<typename T> 2: struct Point 3: { 4: static_assert(is_arithmetic<T>::value, "T is arithmetic!"); 5: T x, y; 6: };
これで最初のプログラムをビルドするとエラー出力として
T is arithmetic!
と自分で書いた文章が出てきます。
static_assertは第1引数の条件が真でない時、第2引数の文をエラーとして出すという機能になります。
このstatic_assertの利点は、このコンパイル時にエラーとして出してくれるところにあります。
これによって、わざわざ実行しなくとも間違いを検出することが出来ます。
ちなみに今回のstatic_assertの第1引数はC++11の追加ライブラリの<type_traits>の機能で、
算術型であるかのチェックになります。
※<type_traits>は説明しませんが、算術型、ポインタ型、配列型など複数の型チェック機能があるためstatic_assertと組合わせると強力です。
static_assertを使わなくとも、プログラムを作ることに問題はありませんが、もしこれから先、安全性の高いコードを作るという場合があったら使うようにしてください。
以上でstatic_assertの説明を終わります。