Aggregates 集成体
以下staticデータメンバと明示しない限り、非staticデータメンバを単にデータメンバと表現します。
Aggregates とは
Aggregates(以下、集成体)は配列と、以下の条件を満たしたクラスです。
- ユーザ定義のコンストラクタ(コピー、ムーブ含む)が無いこと。つまりコンストラクタは全く記述されていないか、default指定されている状態。
- 全てのデータメンバがpublicであること。staticデータメンバの可視性は影響しない。
- 基本クラスが無いこと
- 仮想関数が無いこと
struct Base {}; // 集成体ではない class B : Base { // 基本クラスがある // publicではないデータメンバ int a; public: // 仮想関数 virtual void f() {} // ユーザ定義コンストラクタ B(B const&) {} }; // 集成体 struct A { double d; B b; void g() {} }; // 集成体 B bs[3];
注意点
- 集成体のデータメンバが非集成体でも良い。可視性以外にデータメンバ自体に要求されるコンセプトはない
- データメンバがインライン初期化を持っていても良い
- 以上より、あるクラスが集成体を満たす時TriviallyCopyableやTriviallyDefaultConstructibleとは限らないし、StandardLayoutとも限らない
#include <type_traits> struct X { virtual void f() {} }; struct aggregate { X x; int i; }; int main() { aggregate agg = {{}, 42}; static_assert(!std::is_trivially_copy_constructible<aggregate>{}, ""); static_assert(!std::is_trivially_default_constructible<aggregate>{}, ""); static_assert(!std::is_standard_layout<aggregate>{}, ""); }
特徴
集成体はC言語の構造体と同じような初期化が行えるという特徴があります。
集成体だとできること
集成体を初期化リストで初期化した場合、初期化リストの要素の順序と集成体のデータメンバの順序が対応します。それぞれの要素がコピーされ初期化されます。
A a = {0.0, B{}};
配列数より初期化リストが足りない場合、初期化リストで明示的に初期化されなかったデータメンバ(仮に型Tとする)は={}
またはT{}
されたのと同じ効果の初期化が行われます。つまりゼロ初期化になります。
A as[3] = {A{}, {}}; //OK A as2[3] = {}; // OK
要素が非集成体の場合は省略することはできず、明示的に初期化しなければなりません。
B bs[3] = {B{}, B(), {}}; // もしB(int)があった場合 B bs3[] = {1, B{2}, B(3), {4}};
B(int)がexplicit指定されていた場合、B(1)
とB{1}
はOKですが、1
と{1}
はNGです。
参考
N4431 §8.5.1