ゆとりーなの日記

日記的な事を書いて行くと思はれる

猫でもわかるtypename入門

最近C++界隈ではテンプレートメタプログラムが流行っているのでここでtypenameの付け方をおさらいしておきましょう。

struct foo {
  typedef int type;
};

template <typename T>
void hoge(T t) {
  const T::type a = 0;
}

int main() {
  foo f;
  hoge(f);
}

先ず、上のコードは一般的なC++コンパイラではコンパイルが通りません。T::typeがネストされた依存型名なのでtypenameが必要です。よって正しくは次のように書きます。

struct foo {
  typedef int type;
};

template <typename T>
void hoge(T t) {
  const typename T::type a = 0;
}

int main() {
  foo f;
  hoge(f);
}

なお、VC++は一般的なC++コンパイラではないのでこの限りではありません。
続いて次のコードです。

struct foo {
  typedef int type;
};

template <typename T>
T::type hoge(T t) {
  const typename T::type a = 0;
  return 0;
}

int main() {
  foo f;
  const int a = hoge(f);
}

今度はhogeの戻り値の型がネストされた依存型名なのにtypenameが付いていません。因って正しくはこう書きます。

struct foo {
  typedef int type;
};

template <typename T>
typename T::type hoge(T t) {
  const typename T::type a = 0;
  return 0;
}

int main() {
  foo f;
  const int a = hoge(f);
}

なお、VC++でも戻り値がネストされた依存型名の場合はtypenameを付けてあげないといけません。
更に続いて次のコードです。

struct foo {
  typedef int type;
};

template <typename T>
typename T::type hoge(T t) {
  const typename typename T::type a = 0;
  return 0;
}

int main() {
  foo f;
  const int a = hoge(f);
}

これもコンパイルは通りません。typenameは無尽蔵に付けていいものではないのです。用法、用量は守って使ってください。
なお、VC++は一般的なC++コンパイラではないのでこの限りではありません。
次で最後です。もう少しお付き合いください。

struct foo {
  typedef int type;
};

template <typename T>
typename T::type hoge(T t) {
  const typename T::type a = 0;
  return 0;
}

int main() {
  foo f;
  const typename foo::type a = hoge(f);
}

C++0xではtypenameを付けられる箇所が増えているのでtypename foo::typeの様に書くことができます。
なお、中途半端にC++0x対応をしており無尽蔵なtypename修飾を許可するVC++をもってしても、ここでtypenameを付けてしまうと即座にコンパイルエラーとなります。