迭代

2009-07-11 78 views
1

時,爲什麼你不能用一個模板編譯時:迭代

#include <vector> 

template<class T> class foo { 

    void bar() { 
     std::vector<T> x; 
     std::vector<T>::iterator i = x.begin(); 

    } 
}; 


int main() { 
    return 0; 
} 

我得到:

# g++ ~test.cpp 
test.cpp: In member function `void foo<T>::bar()': 
test.cpp:7: error: expected `;' before "i" 

不應該工作的呢?

RHEL上的g ++版本3.4.3。

回答

7

你可以,但你需要告訴它iterator有一個類型(它不知道,因爲一般來說它可以取決於T - 因爲vector是一個模板類型,理論上可以有一些專門化T其中iterator是一個函數或別的東西)。所以,你必須使用typename表明,它始終是一個類型:

typename std::vector<T>::iterator i = x.begin(); 
1

這應該這樣做:

template<class T> class foo { 

    void bar() { 
     std::vector<T> x; 
     typename std::vector<T>::iterator i = x.begin(); 

    } 
}; 

我引用IBM C++編譯器手冊:

typename關鍵字(僅限C++)如果您有一個 限定名稱引用類型,請使用 關鍵字typename並取決於模板參數。 僅在 模板聲明和定義中使用關鍵字typename。 下面的例子說明了使用 關鍵字類型名的:

template<class T> class A 
{ 
    T::x(y); 
    typedef char C; 
    A::C d; 
} 

聲明T :: X(Y)是不明確的。它可以是函數x()的一個調用,它可以是一個 非本地參數y,或者它可以是一個 變量y的聲明,其類型爲 T :: x。 C++將把這個 語句解釋爲一個函數調用。爲了讓編譯器將 聲明解釋爲聲明,請將 添加到 開頭的關鍵字typename。聲明A :: C d; 不合格。 A類也指 至A,因此取決於模板 參數。您必須將關鍵字 typename添加到此 聲明的開頭:

typename A :: C d;您還可以使用 關鍵字類型名稱來代替模板參數 聲明中的 關鍵字類。

0

如果不清楚編譯器不知道它是什麼類型的話,那麼編譯器解析模板foo時,它不知道你以後不會這樣做:

namespace std { 
    template<> 
    class vector<int> { 
     int iterator(void); 
    }; 
} 

然後實例化foo<int>。然後vector<T>::iterator將是一個函數,而不是一個類型,並且foo中的相關行應該解析失敗。爲了在沒有幫助的情況下工作,編譯器將不得不解析foo直到它被實例化,並且他們找到了正確的類來確定'iterator'是一個類型表達式還是一個值表達式。我懷疑這可能會導致循環依賴,但實施起來肯定會特別痛苦。因此,該標準指出,除非聲明,否則假定模板中依賴於參數的表達式不是一種類型。有兩種(我認爲)的方式來說明它是一種類型,它們是(1)用它作爲基類,(2)用typename來限定它。

好的,所以在這個例子中你實際上不允許專門化std :: vector。而矢量實際上有更多的模板參數,而不僅僅是我用過的。因此,在你的例子中,編譯器理論上可以承擔更多的工作。但是該標準沒有特別規定該語言依賴於名稱空間標準庫中哪些模板的知識,因爲(1)意圖是實現可以在普通標頭中實現名稱空間標準,這與編譯器的任何其他標頭一樣(2)C++應該被設計成語言+庫,而不是「具有庫的特殊語法語言」。事實上,(1)和(2)有相同的要求。