class 與 typename 完全等價
template class Widget; // 傳統寫法
template class Widget; // 現代偏好,暗示 T 可為非類別型別
typename 用於「任意型別」,class 保留給「僅限使用者定義類別」 (非標準規定)。模板內出現的名稱分兩類:
int, std::string)。T::iterator, C::const_iterator)。
template
void print2nd(const C& container) {
if (container.size() >= 2) {
C::const_iterator iter(container.begin()); // 錯誤!編譯器假定非型別
++iter;
int value = *iter;
}
}
C::const_iterator 可能是:
typedef ... const_iterator;)。static int const_iterator;)。模板解析時 C 未知,標準規定:預設假定非型別。上例被視為 C::const_iterator * iter(...) (乘法/宣告歧義)。
typename
typename C::const_iterator iter(container.begin()); // 明確告知是型別
鐵律: 凡在模板中使用嵌套依賴型別名稱,必須在其前加 typename。
template
void f(const C& container, // C 非嵌套 → 不需 typename
typename C::iterator iter); // C::iterator 嵌套依賴型別 → 必須 typename
typename (標準例外)。
template
class Derived : public Base::Nested { // 基類列表:不加 typename
public:
Derived(int x) : Base::Nested(x) { // 成員初始化列表基類標識符:不加
typename Base::Nested temp; // 一般使用:必須加 typename
}
};
typedef typename
template
void workWithIterator(IterT iter) {
typedef typename std::iterator_traits::value_type value_type; // 簡化後續使用
value_type temp(*iter);
// ...
}
std::iterator_traits::value_type 為嵌套依賴型別名稱 → 需 typename。typedef 簡化長名稱,typedef typename 雖顯怪異但合乎邏輯。typename 也通過、多加 typename 也通過、必需處拒絕 typename。template <class T> 與 template <typename T> 完全等價。typename (基類列表、成員初始化列表基類標識符除外)。typedef typename ... 簡化複雜型別表達式。