なぜ次のコードが機能するのですか?
struct A {
std::vector<A> subAs;
};
Aは不完全なタイプですよね? A * sのベクトルがあったら、理解できます。しかし、ここではそれがどのように機能するのかわかりません。再帰的な定義のようです。
この paper が採用されました into C++ 17 これにより、特定のSTLコンテナで不完全な型を使用できるようになります。それ以前は、未定義の動作でした。論文から引用するには:
イサクア会議での議論に基づいて、「不完全型のコンテナー」というアプローチで続行することでコンセンサス*を達成しましたが、範囲を
std::vector
、std::list
、およびstd::forward_list
に制限しました、最初のステップとして。
そして、標準の変更については(強調鉱山):
allocatorがallocator-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;
};
技術的には、size
、capacity
、場合によっては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;
};
}