0

我的理解是 typedef 充当类型的同义词,或者可以用作特定类型的别名。此外,下面的简化代码完美构建。这里的问题是,如果我将 main 函数中的第二行更改为:

Array<int>::ArrayIter<T> pa = a.begin(); // substituting back the typedef  “iterator” to its original form of ArrayIter<T>.

我在编译期间收到以下错误消息:

“ArrayIter”不是“Array”的成员</p>

但是使用“typedef”(迭代器)表示法完美编译的代码。为什么“迭代器”和 ArrayIter 突然不再是同义词了:

参考代码如下:

template<class T> class ArrayIter {
public:
ArrayIter(T* p) : m_p(p) {
}

private:
T* m_p;
};

template<class T> class Array {

public:
  Array(int size) throw (const char*) {
    if ( size > 0 ) {
       m_p = new T[size];
       m_size = size;
    } else {
   throw "Array: invalid array dimension";
}
  }

  // typedef and methods to support the new iterator for this class
  typedef ArrayIter<T> iterator;

  ArrayIter<T> begin() {
  return ArrayIter<T>(m_p);
  }

private:
  T* m_p;
  int m_size;
};


int main(int argc, char* argv[]) {

  Array<int> a(10);
  Array<int>::iterator pa = a.begin();

 return 0;
}
4

6 回答 6

1

正如错误所说,ArrayIteris not a member of Array: 它是一个单独的类,在周围的命名空间中声明。因此,Array<int>::ArrayIter<T>是无效的,应该只是ArrayIter<int>.

iterator 的成员Array,因此Array<int>::iterator 有效的,并且是 的别名ArrayIter<int>

于 2012-07-04T16:50:49.050 回答
0

ArrayIter不是内部的嵌套类,Array因此Array::ArrayIter声明无效。ArrayIter仅在全局范围内定义,因此您可以ArrayIter<int> iter = a.begin();. typedefiterator是在内部定义的Array,因此您可以将其作为Array<int>::iterator.

于 2012-07-04T16:49:57.570 回答
0

ArrayIter<T>绝对不是 的成员Array,当它在外面宣布时,怎么可能?

您理解的差距在于范围界定的工作原理。

class A
{
};

A现在是全局命名空间中的类型。现在,让我们假设第二类:

class B
{
public:
    typedef ::A C;
};

C被定义在里面B,所以它的全名是B::C。但是,A仍然在全局命名空间中!typedef将其转换为某物不会改变原始名称的范围,因此在这种情况下A永远不是 的成员。B

总而言之 - 在全局命名空间中,以下(取自您的代码)是相同的:

Array<int>::iterator pa = a.begin();

是相同的

ArrayIter<int> pa = a.begin();
于 2012-07-04T16:50:45.173 回答
0

我没有看到变体之间的任何等效性。ArrayIter不是类型,它是模板。您示例中的 typedef 名称iterator是指ArrayIter模板的特定专业化。里面Array<int>会提到ArrayIter<int>。里面Array<double>会提到ArrayIter<double>。这正是您要求编译器通过您的typedef.

它不会以任何方式将ArrayIter模板带入Array类中。它仍然不是会员。它仍然存在于全局命名空间中,Array<>::iterator只是简单地引用它。

最重要的是,完全不清楚T您要在里面指的是什么main。那里没有T

如果要作为模板ArrayIter引入Array,可以使用 C++11 标准的一个新特性,称为“模板类型定义”或“模板别名声明”

template <typename T>
class Array {
  ...
  template <typename U>  using ArrayIter = ::ArrayIter<U>;
  ...
};

现在您可以Array::ArrayIter用作模板。

于 2012-07-04T16:51:34.377 回答
0

好吧,您说过要“撤消” typedef。您的 typedef 如下所示:

typedef ArrayIter<T> iterator;

当在 Array[int] 中使用时,它“扩展”为

typedef ArrayIter<int> iterator;

所以,给定这条线

Array<int>::iterator pa = a.begin();

使用typedef,你可以手动撤消typedef来获取

ArrayIter<int> pa = a.begin();

效果很好:-)

基本上,typedef 被命名为“Array[int]::iterator”,而不仅仅是“iterator”。

于 2012-07-04T16:54:28.007 回答
0

这是因为您的迭代器是在范围内定义的,Array而您ArrayIter是在全局范围内定义的。要实现你所说的,你应该把ArrayIter里面Array

template<class T> class Array { 

public: 
    template<class T> class ArrayIter { 
    public: 
        ArrayIter(T* p) : m_p(p) { 
        } 

    private: 
        T* m_p; 
    }; 


    Array(int size) throw (const char*) { 
        if ( size > 0 ) { 
            m_p = new T[size]; 
            m_size = size; 
        } else { 
            throw "Array: invalid array dimension"; 
        } 
    } 

    // typedef and methods to support the new iterator for this class 
    typedef ArrayIter<T> iterator; 

    ArrayIter<T> begin() { 
        return ArrayIter<T>(m_p); 
    } 

private: 
    T* m_p; 
    int m_size; 
}; 


int main(int argc, char* argv[]) { 

    Array<int> a(10); 
    Array<int>::ArrayIter<int> pa = a.begin(); 

    return 0; 
} 
于 2012-07-04T17:01:02.067 回答