traits
- 特性。テンプレート引数に渡された型、定数によって動作を切り替える。
例えば、shared_ptr< T >でvoidを渡すと、
shared_ptr< void > p;
operator*()の戻り値の型がvoid&になるのでコンパイルエラーになってしまいます。
template < typename T > class shared_ptr { ... T& operator*()const{ return *ptr; } ... };
- Tがvoid以外→T&
- Tがvoid→void
のように、Tの型によって戻り値の型を選択したいわけです。
ちなみにtemplate内の関数の{...}は呼び出し処理を書かない限りコンパイルされないので、voidでreturnを記述していてもコンパイルエラーになりません。
では、さっそくoperator*()の戻り値の型を決定するための特性クラスを作ってみましょう。
sahred_ptr_traits
//テンプレート引数T&をreference_tに置き換える。 // shared_ptr_traits< T >::reference_t == T& template< typename T > struct shared_ptr_traits { typedef T& reference_t; };
これだけではshared_ptr_traits< void >::reference_tがvoid&になってしまうので、Tがvoidのときだけ、voidをreference_tとします。
//テンプレート引数T&をreference_tに置き換える。 // shared_ptr_traits< T >::reference_t == T& template< typename T > struct shared_ptr_traits { typedef T& reference_t; }; //Tがvoidの時の特殊化バージョン // shared_ptr_traits< void >::reference_t == void template<> struct shared_ptr_traits< void > { typedef void reference_t; };
operator*()を書き換えましょう。
template < typename T > class shared_ptr { ... typename shared_ptr_traits< T >::reference_t operator*()const{ return *ptr; } ... };
長くて読みにくいのでtypedefしましょう。
template < typename T > class shared_ptr { ... typedef typename shared_ptr_traits< T >::reference_t reference_t; ... reference_t operator*()const{ return *ptr; } ... };
テンプレート引数にある型を渡すと、内部で加工されて別の型が返ってくるんですね。
型専用の関数のようです。
これがいわゆる「テンプレートメタプログラミング」です。
boostでも幅広く使われていますね。
次回からテンプレートメタプログラミングも扱っていきたい思います。