type traits(型特性)クラスの利用
またまたc++勉強ネタ。
traitsクラス
traits
クラスは、template
を利用したテクニックの一つです。
標準ライブラリや、boostなどで多用される手法の一つでもあります。
今回は、traits
クラスの基本的な利用法を勉強したいと思います。
traitsクラス
type traits
(型特性)は、型に関する特性を表現するために利用されるクラスです。
traits
には色々なバリエーションがありますが、まず例として、STLのiterator_traits
クラステンプレートを見てみましょう.
traitsを利用した例 std::iterator_traits
std::iterator_traits
は、イテレータに関する型特性を表現するためのクラスで、以下のような構成をしています.
以下のコードはcpprefjp - C++日本語リファレンスから引用しました。
namespace std { template <class Iterator> struct iterator_traits { using difference_type = typename Iterator::difference_type; using value_type = typename Iterator::value_type; using pointer = typename Iterator::pointer; using reference = typename Iterator::reference; using iterator_category = typename Iterator::iterator_category; }; // ポインタに対する特殊化 template <class T> struct iterator_traits<T*> { using difference_type = ptrdiff_t; using value_type = T; using pointer = T*; using reference = T&; using iterator_category = random_access_iterator_tag; }; template<class T> struct iterator_traits<const T*> { using difference_type = ptrdiff_t; using value_type = T; using pointer = const T*; using reference = const T&; using iterator_category = random_access_iterator_tag; }; }
コードを見ると、iterator_traits
は単にtypedef
された型情報を格納しているだけで、メンバを持っていません.
使用者は、適切にこのテンプレートを特殊化することによって、iterator
用に作られたアルゴリズムを利用することができるようになります
traits活用: タグ・ディスパッチ
std::iterator_traits
には、タグ・ディスパッチのために利用する iterator_category
という型を持っています
iterator_category
には、タグ(tag)と呼ばれる空クラスを指定します
標準で用意されているクラスは以下
std::input_iterator_tag
std::output_iterator_tag
std::forward_iterator_tag
std::bidirectional_iterator_tag
std::random_access_iterator_tag
さて、このiterator_category
をどう使うかというと、関数が引数の型によって選択できることを利用します
//こんな感じでディスパッチさせる template <typename InputIterator> void foo(InputIterator itr, std::input_iterator_tag){ } template <typename OutputIterator> void foo(OutputIterator itr, std::output_iterator_tag){ } template <typename Iterator> void foo(Iterator itr){ foo(itr, typename std::iterator_traits<Iterator>::iterator_category()); }
また、std::forward_iterator_tag
などは他のイテレータタグを継承しています
タグが変換可能であれば呼び出しを行えるようになるので、継承がうまく利用されていますね
以上、type traits
の基本でした。この他にもstatic
関数と組み合わせたり、traits
には様々な活用法があるみたいです
いろんなライブラリをよんで勉強していきたいですね!