typedef同义替换

时间:2012-07-04 16:44:51

标签: c++

我的理解是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;
}

6 个答案:

答案 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 iteratorArray中定义,因此您可以Array<int>::iterator访问它。

答案 2 :(得分:0)

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

您理解的差距是确定范围的方式。

class A
{
};

A现在输入全局命名空间。现在,让我们假设第二类:

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

CB内定义,因此它的全名是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; 
}