テンプレートの型を出力する

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() は long[10] と出力するね. OK.

だけど type_descriptor() とすると long[2][10] と出力されるね. これはどうすればよいかな?