繁体   English   中英

C++ 模板类型名迭代器

[英]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 ,但是当外部类仍然依赖模板参数Ttypename必须存在。

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 = ...;

此处提供了有关上述答案的更多背景信息

C++ typename 关键字的描述

我有一个不同但相似的问题,因为我想为子节点 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM