web-dev-qa-db-ja.com

同じクラスのメンバーベクトルを宣言するにはどうすればよいですか?

なぜ次のコードが機能するのですか?

struct A {
    std::vector<A> subAs;
};

Aは不完全なタイプですよね? A * sのベクトルがあったら、理解できます。しかし、ここではそれがどのように機能するのかわかりません。再帰的な定義のようです。

46
DavitS

この paper が採用されました into C++ 17 これにより、特定のSTLコンテナで不完全な型を使用できるようになります。それ以前は、未定義の動作でした。論文から引用するには:

イサクア会議での議論に基づいて、「不完全型のコンテナー」というアプローチで続行することでコンセンサス*を達成しましたが、範囲をstd::vectorstd::list、およびstd::forward_listに制限しました、最初のステップとして。

そして、標準の変更については(強調鉱山):

allocatorallocator-completeness-requirementsを満たす場合、Tをインスタンス化するときに不完全な型vectorを使用できます(17.6.3.5.1 )。 [〜#〜] t [〜#〜]は、結果として得られるベクトルの特殊化のメンバーが参照される前に完了する必要があります。

したがって、それができます。std::allocator<T>をインスタンス化するときにデフォルトのstd::vector<T, Allocator>をそのままにしておくと、論文によると、不完全な型Tで常に機能します。それ以外の場合は、不完全な型Tでインスタンス化できるAllocatorに依存します。


Aは不完全なタイプですよね? A * sのベクトルがあったら、理解できます。しかし、ここではそれがどのように機能するのかわかりません。それは再帰的な定義のようです。

そこには再帰はありません。非常に単純化された形式では、次のようになります。

class A{
    A* subAs;
};

技術的には、sizecapacity、場合によってはallocatorを除いて、std::vectorは、アロケータを介して管理するAの動的配列へのポインタを保持するだけで済みます。 (そして、ポインターのサイズはコンパイル時にわかっています。)

したがって、実装は次のようになります。

namespace std{

    template<typename T, typename Allocator = std::allocator<T>>
    class vector{

        ....

        std::size_t m_capacity;
        std::size_t m_size;
        Allocator m_allocator;
        T* m_data;
    };

}
37
WhiZTiM