【问题标题】:C++ template typename iteratorC++ 模板类型名迭代器
【发布时间】:2012-07-01 18:59:32
【问题描述】:

考虑以下头文件:

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&lt;tNode&lt;T&gt;*&gt;::iterator’ because ‘std::list&lt;tNode&lt;T&gt;*&gt;’ is a dependent scope

我不知道为什么编译器会为此对我大喊大叫。

【问题讨论】:

    标签: c++ templates iterator typename


    【解决方案1】:

    list&lt;tNode&lt;T&gt;*&gt;::iterator 中,您有一个依赖名称,即依赖于模板参数的名称。

    因此,编译器无法检查list&lt;tNode&lt;T&gt;*&gt;(此时它没有定义),因此它不知道list&lt;tNode&lt;T&gt;*&gt;::iterator 是静态字段还是类型。

    在这种情况下,编译器假定它是一个字段,因此在您的情况下它会产生语法错误。要解决这个问题,只需在声明前加上typename 告诉编译器它是一个类型:

    typename list<tNode<T>*>::iterator it
    

    【讨论】:

      【解决方案2】:

      首先,正如其他答案已经指出的那样,嵌套在依赖类型中的类型名称需要在前面加上 typename 关键字。

      当模板完全特化时不需要该关键字,这意味着list&lt;tnode&lt;int&gt;*&gt;::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();
      

      声明将声明一个函数,而不是迭代器。删除()

      【讨论】:

        【解决方案3】:

        list&lt;tNode&lt;T&gt;*&gt;::iterator 是一个依赖名称,一种依赖于模板参数的类型。为了声明该变量,您需要使用 typename 关键字:

        typename list<tNode<T>*>::iterator it = ...;
        

        【讨论】:

          【解决方案4】:

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

          A Description of the C++ typename keyword

          我遇到了一个不同但相似的问题,我想为子节点键入一个迭代器:

          typedef std::vector<NodeType*>::iterator ChildIterator;
          

          这给了我同样的编译器错误。有了这里的建议和上面链接的帮助,我的问题的解决方案是使用

          typedef typename std::vector<NodeType*>::iterator ChildIterator;
          

          改为。

          【讨论】:

            【解决方案5】:

            迭代器可以是嵌套类和类属性

            typename 关键字解决的歧义是,T::iterator(或在您的情况下为 list&lt;tNode&lt;T&gt;*&gt;::iterator)可以引用 nested type(情况 1)或 static class attribute(情况 2)。 默认情况下,编译器将这样的构造解释为案例 2。 typename 关键字强制使用案例 1。

            以下示例分别演示了案例 1 和案例 2 的实现。在这两种情况下,T::iterator * iter; 行都会出现。在第 1 种情况下,它仅在前面带有 typename 参数的情况下才有效。在案例 2 中,它只代表一个双精度(没有任何操作)。星号 * 刚刚被添加,因为它在 case 1 中是指针的指示符,在 case 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。这个答案基本上是一个简短的总结。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-03-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-05-24
              • 1970-01-01
              相关资源
              最近更新 更多