[英]C++ template typename iterator
考慮以下頭文件:
template <typename T> struct tNode
{
T Data; //the data contained within this node
list<tNode<T>*> SubNodes; //a list of tNodes pointers under this tNode
tNode(const T& theData)
//PRE: theData is initialized
//POST: this->data == theData and this->SubNodes have an initial capacity
// equal to INIT_CAPACITY, it is set to the head of SubNodes
{
this->Data = theData;
SubNodes(INIT_CAPACITY); //INIT_CAPACITY is 10
}
};
現在考慮來自另一個文件的一行代碼:
list<tNode<T>*>::iterator it(); //iterate through the SubNodes
編譯器給了我這個錯誤信息: Tree.h:38:17: error: need 'typename' before 'std::list<tNode<T>*>::iterator' because 'std::list<tNode<T>*>' is a dependent scope
我不知道為什么編譯器會為此對我大喊大叫。
在list<tNode<T>*>::iterator
,您有一個依賴名稱,即依賴於模板參數的名稱。
因此,編譯器無法檢查list<tNode<T>*>
(此時它沒有定義),因此它不知道list<tNode<T>*>::iterator
是否是靜態字段或類型。
在這種情況下,編譯器假定它是一個字段,因此在您的情況下它會產生語法錯誤。 為了解決這個問題,只是告訴編譯器,它是一種通過把一個typename
聲明的未來:
typename list<tNode<T>*>::iterator it
首先,正如其他答案已經指出的那樣,嵌套到依賴類型中的類型名稱需要在前面加上typename
關鍵字。
當模板完全特化時不需要該關鍵字,這意味着list<tnode<int>*>::iterator
不需要typename
,但是當外部類仍然依賴模板參數T
, typename
必須存在。
template <typename T> void foo() {
list<tnode<int>*>::iterator it1; // OK without typename
typename list<tnode<T>*>::iterator it2; // typename necessary
}
其次,即使使用typename
typename list<tNode<T>*>::iterator it();
聲明將聲明一個函數,而不是一個迭代器。 刪除()
。
list<tNode<T>*>::iterator
是一個依賴名稱,一種依賴於模板參數的類型。 為了聲明該變量,您需要使用typename
關鍵字:
typename list<tNode<T>*>::iterator it = ...;
此處提供了有關上述答案的更多背景信息
我有一個不同但相似的問題,因為我想為子節點 typedef 一個迭代器:
typedef std::vector<NodeType*>::iterator ChildIterator;
這給了我同樣的編譯器錯誤。 有了這里的建議和上面鏈接的幫助,我的問題的解決方案是使用
typedef typename std::vector<NodeType*>::iterator ChildIterator;
反而。
typename
關鍵字解決的歧義是, T::iterator
(或在您的情況下list<tNode<T>*>::iterator
)可以指代nested type
(情況 1)或static class attribute
(情況 2) . 默認情況下,編譯器將這樣的構造解釋為 case 2。 typename
關鍵字強制使用 case 1。
下面的示例分別演示了案例 1 和案例 2 的實現。在這兩種情況下,行T::iterator * iter;
出現。 在第 1 種情況下,它僅對前面的typename
參數有效。 在第 2 種情況下,它僅代表一個雙精度值(沒有任何操作)。 星號 * 剛剛添加,因為它在情況 1 中是指針的指示符,在情況 2 中是乘法運算符。
最小的可重復示例
#include <iostream>
template <class T>
void foo1() {
typename T::iterator * iter;
std::cout << "foo1: iter points to: " << iter << std::endl;
}
class class1 {
public:
class iterator // subclass
{
};
};
template <class T>
void foo2() {
double iter = 2.;
T::iterator * iter;
std::cout << "foo2: \"T::iterator * iter\" is a simple double: " << T::iterator * iter << std::endl;
}
class class2 {
public:
constexpr static double iterator = 11.;
};
int main()
{
foo1<class1>();
foo2<class2>();
// foo1<class2>(); // does not compile
// foo2<class1>(); // does not compile
return 0;
}
輸出
foo1: iter points to: 0x4010b0
foo2: "T::iterator * iter" is a simple double: 22
感謝trueter指出文章A Description of the C++ typename keyword 。 這個答案基本上是一個簡短的總結。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.