C++17coreadvanced
Aggregate Initialization with Base Classes
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
Aggregates can now have public base classes. Aggregate initialization uses braces to initialize the base class sub-objects first, followed by the derived class members. This removes the need for boilerplate constructors in simple derived types.
Real-World Scenario
Create a lightweight derived configuration struct that extends a base settings struct without writing any constructors.
Quick Snippet
snippet.cpp
struct Point {
double x, y;
};
struct LabeledPoint : Point {
std::string label;
};
// Aggregate initialization including the base class
LabeledPoint lp = {{1.0, 2.0}, "Origin"};
std::cout << lp.label << " at (" << lp.x << ", " << lp.y << ")\n";Full Example
aggregate_init_base.cpp
// CodeNebula - C++17 Example: Aggregate Initialization with Base Classes
// Compile: g++ -std=c++17 -Wall -Wextra -o example aggregate_init_base.cpp
// Demonstrates C++17 aggregate initialization for types with base classes.
// Before C++17, a class with base classes could not be an aggregate. Now,
// public non-virtual base classes can be initialized with brace-enclosed
// initializer lists.
#include <iostream>
#include <string>
// ------------------------------------------------------------------
// 1. Simple base + derived aggregate
// ------------------------------------------------------------------
struct Point2D {
double x;
double y;
};
struct Point3D : Point2D {
double z;
};
// Point3D is an aggregate in C++17: base class members come first
// ------------------------------------------------------------------
// 2. Multiple base classes
// ------------------------------------------------------------------
struct Name {
std::string first;
std::string last;
};
struct Age {
int years;
};
struct Person : Name, Age {
std::string email;
};
// Person has: first, last (from Name), years (from Age), email (own)
// ------------------------------------------------------------------
// 3. Nested aggregate with base
// ------------------------------------------------------------------
struct Color {
int r, g, b;
};
struct Pixel : Point2D, Color {
float alpha;
};
// ------------------------------------------------------------------
// 4. Empty base optimization still works
// ------------------------------------------------------------------
struct Tag {};
struct TaggedValue : Tag {
int value;
std::string label;
};
int main()
{
// 1. Single base
std::cout << "=== Point3D (single base) ===" << std::endl;
Point3D p = {{1.0, 2.0}, 3.0}; // {Point2D{x, y}, z}
std::cout << " x=" << p.x << ", y=" << p.y << ", z=" << p.z << std::endl;
// Also works without inner braces (flattened)
Point3D p2 = {4.0, 5.0, 6.0};
std::cout << " x=" << p2.x << ", y=" << p2.y << ", z=" << p2.z << std::endl;
// 2. Multiple bases
std::cout << "\n=== Person (multiple bases) ===" << std::endl;
Person person = {{"Alice", "Smith"}, {30}, "alice@example.com"};
std::cout << " Name : " << person.first << " " << person.last << std::endl;
std::cout << " Age : " << person.years << std::endl;
std::cout << " Email: " << person.email << std::endl;
// 3. Complex nested aggregate
std::cout << "\n=== Pixel (two bases) ===" << std::endl;
Pixel px = {{10.0, 20.0}, {255, 128, 0}, 0.75f};
std::cout << " pos : (" << px.x << ", " << px.y << ")" << std::endl;
std::cout << " color: (" << px.r << ", " << px.g << ", " << px.b << ")" << std::endl;
std::cout << " alpha: " << px.alpha << std::endl;
// 4. Empty base
std::cout << "\n=== TaggedValue (empty base) ===" << std::endl;
TaggedValue tv = {{}, 42, "answer"}; // {} for empty Tag base
std::cout << " value: " << tv.value << std::endl;
std::cout << " label: " << tv.label << std::endl;
// 5. Array of aggregates with bases
std::cout << "\n=== array of Point3D ===" << std::endl;
Point3D points[] = {
{{0, 0}, 0},
{{1, 0}, 0},
{{0, 1}, 0},
{{1, 1}, 1}
};
for (const auto& pt : points) {
std::cout << " (" << pt.x << ", " << pt.y << ", " << pt.z << ")" << std::endl;
}
return 0;
}
/*
Expected output:
=== Point3D (single base) ===
x=1, y=2, z=3
x=4, y=5, z=6
=== Person (multiple bases) ===
Name : Alice Smith
Age : 30
Email: alice@example.com
=== Pixel (two bases) ===
pos : (10, 20)
color: (255, 128, 0)
alpha: 0.75
=== TaggedValue (empty base) ===
value: 42
label: answer
=== array of Point3D ===
(0, 0, 0)
(1, 0, 0)
(0, 1, 0)
(1, 1, 1)
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example aggregate_init_base.cpp