0

私の理解では、typedef は型のシノニムとして機能するか、特定の型のエイリアスとして使用できます。また、以下の単純化されたコードは完全に構築されています。ここでの質問は、メイン関数の 2 行目を次のように変更した場合です。

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<T>は間違いなく のメンバーではありませんArray。外部で宣言されている場合、どうしてでしょうか?

あなたの理解のギャップは、スコーピングがどのように機能するかです。

class A
{
};

Aがグローバル名前空間に入力されるようになりました。ここで、2 番目のクラスを想定しましょう。

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は、「テンプレート typedef」または「テンプレート エイリアス宣言」と呼ばれる C++11 標準の新機能を使用できます。

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

Array::ArrayIterこれでテンプレートとして使用できます。

于 2012-07-04T16:51:34.377 に答える
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 に答える
0

ArrayIter内部でネストされたクラスではないArrayため、Array::ArrayIter無効な宣言になります。ArrayIterはグローバル スコープでのみ定義されるため、次のことができArrayIter<int> iter = a.begin();ます。typedefiteratorは内部Arrayで定義されているため、 としてアクセスできますArray<int>::iterator

于 2012-07-04T16:49:57.570 に答える
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 は単に "iterator" ではなく "Array[int]::iterator" という名前になります。

于 2012-07-04T16:54:28.007 に答える