[英]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.