2011-10-27 28 views
43

可能重複:
Officially, what is typename for?
Where and why do I have to put the template and typename keywords?何時需要「typename」關鍵字?

考慮下面的代碼:

template<class K> 
class C { 
    struct P {}; 
    vector<P> vec; 
    void f(); 
}; 

template<class K> void C<K>::f() { 
    typename vector<P>::iterator p = vec.begin(); 
} 

爲什麼在這個例子中, 「類型名」 必要的關鍵字? 是否有其他情況下必須指定「typename」?

+0

http://stackoverflow.com/questions/610245/where-and-why-do-我必須把模板和類型名稱的依賴名稱 –

回答

58

簡短回答:每次引用的嵌套名稱是從屬名稱,即嵌套在具有未知參數的模板實例中。

長答案:C++中有三層實體:值,類型和模板。所有這些都可以有名稱,並且名稱本身並不會告訴你它是哪一層實體。相反,關於名稱實體性質的信息必須從上下文中推斷出來。

每當這個推斷是不可能的,你必須指定它:

template <typename> struct Magic; // defined somewhere else 

template <typename T> struct A 
{ 
    static const int value = Magic<T>::gnarl; // assumed "value" 

    typedef typename Magic<T>::brugh my_type; // decreed "type" 
    //  ^^^^^^^^ 

    void foo() { 
    Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template" 
    //  ^^^^^^^^ 
    } 
}; 

這裏的名字Magic<T>::gnarlMagic<T>::brughMagic<T>::kwpq不得不被expliciated,因爲它是不可能告訴:由於Magic是一個模板時,非常性質類型Magic<T>取決於T - 例如,可能存在與主模板完全不同的專業化。

什麼令Magic<T>::gnarl成爲獨立名稱是因爲我們在模板定義中,其中T未知。如果我們使用了Magic<int>,這將是不同的,因爲編譯器知道(你保證!)Magic<int>的完整定義。如果你想自己測試一下,你可以使用Magic的一個示例定義,爲了簡潔起見,請特別注意在專門化中使用constexpr;如果你有一個老的編譯器,可以隨意更改靜態成員常量聲明舊式預C++ 11形式)

template <typename T> struct Magic 
{ 
    static const T     gnarl; 
    typedef T &      brugh; 
    template <typename S> static void kwpq(int, char, double) { T x; } 
}; 
template <> struct Magic<signed char> 
{ 
    // note that `gnarl` is absent 
    static constexpr long double brugh = 0.25; // `brugh` is now a value 
    template <typename S> static int kwpq(int a, int b) { return a + b; } 
}; 

用法:

int main() 
{ 
    A<int> a; 
    a.foo(); 

    return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here! 
} 
+0

@Nils:'const'不是有效的C++。 –

+0

感謝您的解釋。但我無法理解最後一件事:由於名稱'Magic :: kwpq'依賴於模板參數'T',這將在*兩階段查找的第二階段中解決*,對嗎?那麼爲什麼編譯器當時不能檢查(當他能夠確定'kwpq'是一個模板還是一個類型或者其他什麼的時候),如果這個名字根據它的*層實體*正確使用的話? –

+0

@PaoloM:類模板「A」的成員函數的定義必須在第一階段解析,因此您需要對語法進行消歧纔有意義。在第二階段,我們檢查實例'Magic '爲具體類型'T'實際上有一個'kwpq'成員,它是具有適當簽名的函數。 (並感謝編輯!) –

7

需要typename關鍵字每當類型名稱取決於模板參數,(所以編譯器可以「知道」的標識符()的語義,而不在所述第一具有全符號表通過)。


不在同一個意思,有點不太常見,孤獨typename關鍵字也可以使用通用的模板參數時是有用的:http://ideone.com/amImX

#include <string> 
#include <list> 
#include <vector> 

template <template <typename, typename> class Container, 
      template <typename> class Alloc = std::allocator> 
struct ContainerTests 
{ 
    typedef Container<int, Alloc<int> > IntContainer; 
    typedef Container<std::string, Alloc<int> > StringContainer; 
    // 
    void DoTests() 
    { 
     IntContainer ints; 
     StringContainer strings; 
     // ... etc 
    } 
}; 

int main() 
{ 
    ContainerTests<std::vector> t1; 
    ContainerTests<std::list> t2; 

    t1.DoTests(); 
    t2.DoTests(); 
} 
+0

我從來不知道ab出來「孤獨的類型名稱」之前,這很酷! –

10

typename關鍵字,是必要的,因爲iteratorP上的依賴類型。編譯器無法猜測iterator是否指向一個值或一個類型,所以它會假設它的值,除非你叫typename。只要有一個依賴於模板參數的類型,就需要它,在類型或值都是有效的上下文中。例如,由於基類必須是類型,因此不需要基類typename

在同一主題上有一個template關鍵字,用於讓編譯器知道某些從屬名稱是模板函數而不是值。

相關問題