メタ関数1
基本形は以下の通り。
//argを引数として受け取り、そのままtypeとして返すメタ関数 template< typename arg > struct func { typedef arg type; };
型を返す場合はtypedef ... type、値を返す場合はtypedef ... valueとするのが一般的なようです。
単純な使い方。
intを渡すとintがそのまま返ってきます。
func< int >::type a = 1; //int a = 1;
is_void
- 指定した型がvoidかどうか調べる
//デフォルトはfalse template< typename T > struct is_void { static const bool value = false; }; //voidはtrueで特殊化 template<> struct is_void< void > { static const bool value = true; };
特殊化を使うことで、コンパイル時の条件分岐が可能です。
- 使い方
if( is_void< int >::value ) //if( false ) cout << "voidでない" << endl; else cout << "void" << endl;
is_float
- 指定した型が実数型かどうか
//デフォルトはfalse template< typename T > struct is_float { static const bool value = false; }; //floatはtrueで特殊化 template<> struct is_float< float > { static const bool value = true; }; //doubleはtrueで特殊化 template<> struct is_float< double > { static const bool value = true; };
同じ書式が並んで面倒ですね。is_系のメタ関数はboolで結果を返すので、基底にbool_traitsを用意しましょうか。
bool_traits
template< bool val > struct bool_traits; template<> struct bool_traits< true > { typedef bool value_t; static const value_t value = true; }; template<> struct bool_traits< false > { typedef bool value_t; static const value_t value = false; }; typedef bool_traits< true > true_; typedef bool_traits< false > false_;
bool_traits継承版
//指定した型がvoidかどうか template< typename T > struct is_void : false_{}; template<> struct is_void< void > : true_{}; //指定した型が実数型かどうか template< typename T > struct is_float : false_{}; template<> struct is_float< float > : true_{}; template<> struct is_float< double > : true_{};
よく見ると、デフォルトの基本形定義と、型を指定した特殊化バージョンの2つ。マクロを使うと楽できそうです。
マクロ版
#define bool_traits_def( name, value ) \ template< typename T > \ struct name : value##_{}; #define bool_traits_spec( name, type, value ) \ template<> \ struct name< type > : value##_{};
//指定した型がvoidかどうか bool_traits_def( is_void, false ); bool_traits_spec( is_void, void, true ); //指定した型が実数型かどうか bool_traits_def( is_float, false ); bool_traits_spec( is_float, float, true ); bool_traits_spec( is_float, double, true );