テンプレートの型を出力する
C++ Template Metaprogramming の練習問題 2-4
テンプレート パラメータの型をストリームに出力するテンプレート クラス type_descriptor を書け. ただし, パラメータは char, short, int, long からなるコンパウンド型のみに限定してよい.
さらにここでは, cv-クオリファイヤを const だけに限定することにする. 2-4 は boost なしでクリアする問題です.
例えば, type_descriptor はこんな具合に動作する.
std::cout << type_descriptor<int>() << std::endl; // prints "int" std::cout << type_descriptor<long const*&>() << std::endl; // prints "long const*&"
戦略は, type_descriptor をパラメータひとつとるテンプレート クラスとして宣言して, type_descriptor を引数にとる operator<< を定義する. type_descriptor の static メソッド out で出力処理をすることにする.
template<typename T> struct type_descriptor; template<typename T> std::ostream& operator<<(std::ostream& o, const type_descriptor<T>& t) { return type_descriptor<T>::out(o); }
そして, type_descriptor を特殊化していくことにする. まず, int で特殊化してみる.
template<> struct type_descriptor<int> { static std::ostream& out(std::ostream& o) { return o << "int"; } };
これで
std::cout << type_descriptor<int>() << std::endl;
がコンパイル可能になる. 同じように short, long, char についても特殊化する.
次に const, pointer, reference で部分特殊化する.
// Partial specialization for const type. template<typename T> struct type_descriptor<T const> { static std::ostream& out(std::ostream& o) { return type_descriptor<T>::out(o) << " const"; } }; // Partial specialization for pointers. template<typename T> struct type_descriptor<T*> { static std::ostream& out(std::ostream& o) { return type_descriptor<T>::out(o) << "*"; } }; // Partial specialization for references. template<typename T> struct type_descriptor<T&> { static std::ostream& out(std::ostream& o) { return type_descriptor<T>::out(o) << "&"; } };
これで, long const*& みたいなやつにも対応できた. よしよし, いまのところ順調だ. 引数をひとつ取る関数に対する特殊化もやってみよう.
// Partial specialization for functions taking 1 argument. template<typename R, typename A> struct type_descriptor<R(*)(A)> { static std::ostream& out(std::ostream& o) { type_descriptor<R>::out(o) << "(*)("; return type_descriptor<A>::out(o) << ")"; } };
これで, long& (*)(char*) も片付けることができるようになった. 残りはなんだ? 配列やってみようか.
// Partial specialization for arrays with storage size template<typename T, std::size_t N> struct type_descriptor<T[N]> { static std::ostream& out(std::ostream& o) { return type_descriptor<T>::out(o) << "[" << N << "]"; } };
type_descriptor
だけど type_descriptor