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) {}