aggregate data type(aggregate とも)。
C++では、配列や、特定の条件を満たすクラス型(C++)(struct / class / union)を指す。
実用上は、「コンストラクタ呼び出しではなく、{} によってメンバを順番に初期化できる型」と捉えると分かりやすい。
クラス型の集成体
クラス型が集成体であるためには、少なくとも次のような制約がある。
- ユーザー宣言されたコンストラクタを持たない
privateまたはprotectedの非静的データメンバを持たないvirtual関数を持たない
また、基底クラスやその他の細かな条件もあるため、厳密な定義はC++の版によって少し異なる。
ただし、メンバ変数だけを持つ単純な struct は集成体であることが多い。
集成体初期化
集成体は、リスト初期化によってメンバを宣言順に初期化できる。 これを**集成体初期化(aggregate initialization)**という。
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee frank = { 1, 32, 60000.0 }; // コピーリスト初期化
Employee joe { 2, 28, 45000.0 }; // リスト初期化
}通常は、非コピー形式の Employee joe { ... }; のほうが好まれる。
初期化子が足りない場合
初期化子の個数がメンバ数より少ない場合、残りのメンバは次のように初期化される。
- デフォルトメンバ初期化子があればそれを使う
- なければ空の初期化子リストから初期化される
多くの場合、後者は値初期化になる。
struct Employee
{
int id {};
int age {};
double wage { 76000.0 };
double bonus;
};
int main()
{
Employee joe { 2, 28 };
// joe.id = 2
// joe.age = 28
// joe.wage = 76000.0
// joe.bonus = 0.0
}そのため、空の {} を使うと、集成体の各メンバをまとめて初期化しやすい。
Employee joe {};指示付き初期化
C++20では、初期化時にどのメンバへ値を入れるかを明示できる。
struct Foo
{
int a {};
int b {};
int c {};
};
int main()
{
Foo f1{ .a{ 1 }, .c{ 3 } };
Foo f2{ .a = 1, .c = 3 };
}指定しなかったメンバは通常どおり初期化される。
ただし、メンバの指定順は宣言順に従う必要がある。
Foo f3{ .b{ 2 }, .a{ 1 } }; // エラー代入
集成体オブジェクトには、{} を使った代入もできる。
struct Employee
{
int id {};
int age {};
double wage {};
};
int main()
{
Employee joe { 1, 32, 60000.0 };
joe = { 1, 33, 66000.0 };
}C++20 では、指示付き初期化を使った代入も書ける。
Employee joe { 1, 32, 60000.0 };
joe = { .id = joe.id, .age = 33, .wage = 66000.0 };同じ型のオブジェクトで初期化する
集成体も通常のクラス型と同様に、同じ型の別オブジェクトから初期化できる。
struct Foo
{
int a {};
int b {};
int c {};
};
int main()
{
Foo foo { 1, 2, 3 };
Foo x = foo;
Foo y(foo);
Foo z { foo };
}補足
- 集成体は
structに多いが、classやunionでも条件を満たせば集成体になれる std::arrayも集成体である- C++の版によって集成体の厳密な定義は少し変わる