template聲明式中,class和typename這兩個關鍵字意義徹底相同html
template<class T> class Widget;c++
template<typename T> class Widget;spa
有時候你必定要用typename,指針
能夠在template中指涉的兩種名稱:htm
template <typename C>
void print2nd(const C& container)
{
if (container.size() >= 2)
{
C::const_iterator iter(container.begin());
++iter;
int value = *iter;
std::cout << value;
}
}對象iter的類型是C::const_iterator 其實是什麼必須取決於template參數C。template內出現的名稱若是相依於某個template參數,稱之爲從屬名稱(dependent names)。若是從屬名稱在class內呈嵌套狀,稱之爲嵌套從屬名稱(nested dependent name)。C::const_iterator 就是這樣一個名稱嵌套從屬名稱。blog
value類型int。不依賴任何template參數的名稱。稱爲非從屬名稱(non-dependent name)。ci
嵌套從屬名稱可能致使解析的困難:get
template <typename C>
void print2nd(const C& container)
{
C::const_iterator* x;
}編譯器看起來咱們好像聲明一個local變量,是個指針,指向一個C::const_iterator。 但它之因此被那麼認爲,是由於咱們「已經知道」C::const_iterator 是個類型。若是C::const_iterator 不是個類型呢?若是C有個static成員變量碰巧被命名爲const_iterator。過期x碰巧是個global變量名稱,那樣上述代碼就是一個相乘動做,C::const_iterator 乘以x。撰寫c++解析器的人必須操心全部可能的輸入。
在咱們知道C之前,沒有任何辦法能夠知道C::const_iterator 是否爲一個類型。而當編譯器開始解析template print2nd時,還沒有肯定C是什麼東西。
c++有個規則能夠解析此一歧義狀態:若是解析器在template中遭遇一個嵌套從屬名稱,它便假設這個名稱不是個類型,除非你告訴它是。缺省狀況下從屬名稱不是類型。此外還有個例外。
因此上述代碼不是有效的c++代碼。咱們必須告訴c++說C::const_iterator 是個類型。只要緊鄰它以前放置關鍵字typename便可:
template <typename C>//這個合法的c++代碼
void print2nd(const C& container)
{
if (container.size() >= 2)
{
typename C::const_iterator iter(container.begin());
++iter;
int value = *iter;
std::cout << value;
}
}typename只用來驗明嵌套從屬類型名稱;其餘名稱不應有它存在。
template <typename C>
void f(const C& container, //不容許使用typename
typename C::iterator iter);//必定要使用typename「typename必須做爲嵌套從屬類型名稱的前綴詞」這一規則的例外是,typename不能夠出如今base classes list內的嵌套從屬類型名稱以前,也不可在member initialization list(成員初始化列表)中做爲base class修飾符。例如:
template <typename T>
class Derived: public Base<T>::Nested{//base class list中不容許「typename」
public:
explicit Derived(int x)
:Base<T>::Nested(x)//mem.init.list中不容許「typename」
{
typename Base<T>::Nested temp;//嵌套從屬類型既不在base class list中也不在mem.init.list中,
} //做爲一個base class修飾符需加上typename
};讓咱們看一個typename例子:一個function template,他接受一個迭代器,而咱們打算爲該迭代器指涉的對象作一份復件temp:
template <typename IterT>
void workWithIterator(IterT)
{
typename std::iterator_traits<IterT>::value_type temp(*iter);
}這是個標準trait class的一種運用(條款47),至關於說「類型IterT之對象所指之物的類型」。若是IterT是vector<int>::iterator,temp的類型就是int,若是IterT是list<string>::iterator,temp的類型就是string。因爲std::iterator_traits<IterT>::value_type是個嵌套從屬類型名稱(value_type被嵌套於iterator_traits<IterT>以內而IterT是個template參數),因此必須在它以前放置typename。
這麼長你確定會想創建一個typedef。對於traits成員名稱如value_type,廣泛習慣是設定typedef名稱用以表明某個traits成員名稱:
template <typename IterT>
void workWithIterator(IterT)
{
typedef typename std::iterator_traits<IterT>::value_type value_type;
value_type temp(*iter);
}