C++ テンプレート宣言時のclassとtypenameの違いと使い分け

C++のテンプレート宣言時には、型名を明示する際にtypenameキーワードとclassキーワードを用いることができます。ただし、両キーワードに機能的な違いはありません。

// いずれもコンパイラ側では区別されない
template<typename T> void f() {}
template<class T>    void f() {}

ただ場合によっては、明確なコードを実現するために両キーワードを使い分けることがあります。例えば、クラス型をclassキーワードで受け取るようにし、int型などの基本型はtypenameで受け取るようするといった具合です。

template<class T, typename U> void push_back(T& t, U u) {
  t.push_back(u);
}

std::vector<int> v;
push_back(v, 9);

ただし両キーワードの使い分けを行わず、classキーワードの利用で統一するという考え方もあります。これにより、依存型を取得する際に利用されるtypename指定子との明確な区別が可能となります。

// 両機能が明確に区別され読みやすい
template<class T, class U = typename T::value_type> void f() {}
// 合理的だが解釈に戸惑う(複雑な文になるとさらに混乱する)
template<class T, typename U = typename T::value_type> void f() {}

ちなみにC++14以前のC++ではテンプレートテンプレート仮引数の宣言にtypenameキーワードを利用することができないため、代わりにclassキーワードを用いる必要があります。

/* エラーまたは警告が発生する */
// warning: template template parameter using 'typename' is a C++1z extension [-Wc++1z-extensions]
template<template<class U> typename T, class U> void f(const T<U>& v) {}
// OK
template<template<class U> class    T, class U> void f(const T<U>& v) {}

広告