2

という名前のクラスがAあり、このクラスには反復可能なコンテナーがあり、順序、空などのいくつかのアクセス規則に従って反復処理を行います。

次の例を単純化するために、コンテナーを反復処理しているだけだと考えてみましょう。ただし、組み込みのコンテナーの iteratorを使用してこれを行うことはできません

class A {
public:
    class iterator {
    public:
        // Constructor
        iterator() {
        }
        // Destructor
        ~iterator() {
        }
        // Advances the iterator
        void operator++() {
           // Some accessing policy
        }
    };
private:
    std::vector<int> a;
};

すべてが非常にうまく機能し、非常にきれいに見えますが、イテレーターを宣言するときに使用する必要があることを除いて、typenameこれはコンパイラーに私が持っているものが型であることを伝えるために使用されるとほとんど想定しています。クラスのインスタンス化自体ではありません。

質問:

  1. なぜ使用する必要があるのtypenameですか:

    A a;
    for (typename A::iterator it(...); it != ...; ++it) {
    }
    
  2. typenameベクトル反復子はタグを必要としないため、反復子は一般的にどのように定義されていますか? ベクトル自体からではなく、クラス定義からベクトルを宣言することと関係がありますか?

    std::vector<int> v;
    for (std::vector<int>::iterator it(v.begin()); it != v.end(); ++it) {
    }
    
  3. イテレータはコンテナ クラス内で定義されていますか (コンポジションという名前だと思います)、そうでない場合は、次のようにイテレータがクラスの名前空間にどのように追加されますか?

    std::vector<int>::iterator it;
    
4

2 に答える 2

4

1 - なぜ使用する必要があるのtypenameですか: [...]

を使用する必要はありませんtypename。依存型の修飾型名を使用している場合は、テンプレートtypenameで曖昧さ回避ツールが必要です。StackOverflow に関するこの Q&A は、物事を明確にします。これ:

A a;
typename a::iterator it; // ERROR!

違法なC++ です。テンプレートAパラメーターの名前でない場合は、次のようにする必要があります。

A::iterator it;

テンプレート内にいてA、次のようなテンプレート パラメーターの名前である場合:

template<typename A>
struct X
{
    void foo()
    {
        typename A::iterator it;
    //  ^^^^^^^^
    //  This is necessary here!
    }
};

次に、 の後に続くものが型の名前であるtypenameことをコンパイラに伝えるために使用する必要があります。::


typename2 - ベクトル反復子はタグを必要としないため、反復子は一般的にどのように定義されていますか?

繰り返しますが、「ベクター反復子にタグが必要ない」というのtypenameは正しくありません。次のように、そのベクトルの明示的な特殊化がある場合:

std::vector<int>::iterator it; // "typename" not required

thentypenameでは必要なかったので、必要ありませんA::iterator it。ただし、次の場合のようにテンプレート内にいる場合は、必須になります。

template<typename A>
struct X
{
    void foo()
    {
        typename std::vector<A>::iterator it;
    //  ^^^^^^^^
    //  This is necessary here!
    }
};

これstd::vector<A>::iteratorは、修飾された従属型名がここにあるためです。


3 - イテレータはコンテナ クラス内で定義されていますか (コンポジションという名前だと思います)、そうでない場合は、[..] のようにイテレータがクラスの名前空間にどのように追加されますか

これは、ネストされたクラスを定義するか、単純に型エイリアスを使用して行うことができます。

template<typename T>
struct X
{
    typedef T* iterator;
    iterator begin() { /* ... */ }
    // ...
};

X<int>::iterator it; // OK: "typename" not required

template<typename T>
void foo(X<T>& x)
{
    typename X<T>::iterator it = x.begin();
//  ^^^^^^^^
//  This is necessary here!

    // ...
}
于 2013-03-09T14:44:16.677 に答える
1

あなたのコード例には多くの問題があるので、これがあなたが探している答えかもしれません (手を振る) :) もちろん、あなたの例が正しくない場合、すべての賭けはオフです。

これがまったく機能することに驚いています。「a」は変数、「A」はクラスです。

また、デフォルトのコンストラクターで変数を宣言するときは、終わりの括弧 () を使用しません。

A a;
A::iterator it;
for (A::iterator it; it != ...; ++it) {
}

また、反復子はコンテナー クラス内で定義されます。typename を使用する必要があるのは、テンプレートを扱っている場合と、静的メンバーまたは関数/ネストされたクラスまたは typedef のいずれかとして解釈される可能性のあるものにアクセスする場合のみです。これは、Andy Prowl からも提供されたこちらの回答でさらに説明できます。

幸運を

于 2013-03-09T15:19:29.240 に答える