我的理解是typedef充当类型的同义词,或者可以用作特定类型的别名。此外,下面的简化代码完美地构建。这里的问题是我是否将main函数中的第二行更改为:
Array<int>::ArrayIter<T> pa = a.begin(); // substituting back the typedef “iterator” to its original form of ArrayIter<T>.
我在编译期间收到以下错误消息:
“ArrayIter”不是“Array”的成员
但代码使用“typedef”(迭代器)表示法完美编译。为什么“iterator”和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;
}
答案 0 :(得分:1)
正如错误所述,ArrayIter
不是Array
的成员:它是一个单独的类,在周围的命名空间中声明。因此,Array<int>::ArrayIter<T>
无效,应为ArrayIter<int>
。
iterator
是Array
的成员,因此Array<int>::iterator
有效,并且是{{1}的别名}。
答案 1 :(得分:0)
ArrayIter
不是Array
内的嵌套类,因此Array::ArrayIter
将是无效声明。 ArrayIter
仅在全局范围内定义,因此您可以ArrayIter<int> iter = a.begin();
。 typedef iterator
在Array
中定义,因此您可以Array<int>::iterator
访问它。
答案 2 :(得分: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();
答案 3 :(得分: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标准的新功能,称为“模板typedef”或“模板别名声明”
template <typename T>
class Array {
...
template <typename U> using ArrayIter = ::ArrayIter<U>;
...
};
现在您可以使用Array::ArrayIter
作为模板。
答案 4 :(得分: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”。
答案 5 :(得分: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;
}