C++20 introduced Designated Initializers, a feature borrowed from C99, allowing you to initialize structs by explicitly specifying member variable names. This greatly improves code readability and maintainability.
Basic Concepts
Designated initializers use the syntax .member_name = value to explicitly specify the members to be initialized.
Traditional initialization (Pre-C++20):
1
2
3
4
5
6
7
8
9
10
11
| struct Point {
int x;
int y;
int z;
};
// Must follow declaration order, error-prone
Point p1 = {1, 2, 3}; // Which is x, y, z?
// Adding a member requires updating all initialization code
Point p2 = {1, 2}; // z is 0, but it's not obvious
|
Designated Initializers (C++20):
1
2
3
4
5
6
7
8
9
10
11
| struct Point {
int x;
int y;
int z;
};
// Clear and explicit
Point p1 = {.x = 1, .y = 2, .z = 3};
// Can skip certain members (unspecified members are zero-initialized)
Point p2 = {.x = 1, .z = 3}; // y = 0
|
Important Rules
- Must follow declaration order
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| struct Person {
std::string name;
int age;
std::string city;
};
// ✅ Correct: Follows declaration order
Person p1 = {
.name = "Alice",
.age = 30,
.city = "Beijing"
};
// ❌ Error: Violates declaration order
Person p2 = {
.age = 30, // age comes after name
.name = "Bob", // Compilation error: "name": designator must appear in the order of member declaration of class "Person"
.city = "Shanghai"
};
|
- Can skip members
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| struct Person {
std::string name;
int age;
std::string city;
};
Person p1 = {
.name = "Alice",
.age = 30,
};
Person p1 = {
.age = 30
};
|
- Cannot mix initialization styles
1
2
3
4
5
6
7
8
9
10
| struct Point {
int x, y, z;
};
// ❌ Error: Cannot mix
Point p = {1, .y = 2, .z = 3}; // Compilation error!
// ✅ Correct: Use one style consistently
Point p1 = {1, 2, 3}; // Positional initialization
Point p2 = {.x = 1, .y = 2, .z = 3}; // Designated initialization
|
- Each member can only be initialized once
1
2
3
4
5
6
7
8
9
| struct Point {
int x, y, z;
};
// ❌ Error: Duplicate initialization
Point d = {
.x = 10,
.x = 20 // Error!
};
|
- Cannot use designators for array elements
1
2
3
4
5
6
7
8
| struct Point {
int coords[3];
};
// ✅ Allowed for the array itself
Point p = {.coords = {1, 2, 3}};
// ❌ Cannot do this (unlike C99)
Point p1 = {.coords[0] = 1, .coords[1] = 2}; // Error in C++!
|
- Only applicable to aggregate types
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // ✅ Aggregate type: No user-defined constructors
struct Aggregate {
int x;
double y;
};
Aggregate a = {.x = 1, .y = 2.0}; // Correct
// ❌ Non-aggregate type: Has a constructor
struct NonAggregate {
int x;
double y;
NonAggregate(int x, double y) : x(x), y(y) {}
};
NonAggregate na = {.x = 1, .y = 2.0}; // Error! Designated initialization can only be used to initialize aggregate class types
|
Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| struct ServerConfig {
std::string host = "localhost";
int port = 8080;
int timeout = 30;
bool useSSL = false;
int maxConnections = 100;
};
// Clearly create different configurations
ServerConfig devConfig = {
.port = 3000,
.timeout = 60
};
ServerConfig prodConfig = {
.host = "api.example.com",
.port = 443,
.useSSL = true,
.maxConnections = 1000
};
|
Nested structures:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| struct Address {
std::string street;
std::string city;
};
struct Employee {
std::string name;
Address address;
double salary;
};
// Nested designated initialization
Employee emp = {
.name = "Job",
.address = {
.street = "Street 1",
.city = "US",
},
.salary = 75000.0
};
|
Comparison with C99
C++ designated initializers have some restrictions compared to C99:
| Feature | C99 | C++20 |
|---|
| Out-of-order initialization | ✅ Allowed | ❌ Must be in order |
| Array designators | ✅ [index] | ❌ Not supported |
| Nested designators | ✅ .a.b | ❌ Must use nested braces |
| Mixed initialization | ✅ Allowed | ❌ Not allowed |
1
2
3
4
5
6
7
8
9
10
11
| // Out-of-order
struct Point p1 = {.y = 2, .x = 1}; // Allowed in C99, error in C++20
// Array designators
int arr[5] = {[0] = 1, [4] = 5}; // Allowed in C99, error in C++20
// Nested designators
struct S {
struct { int x, y; } point;
};
struct S s = {.point.x = 1}; // Allowed in C99, error in C++20
|
https://en.cppreference.com/w/cpp/language/aggregate_initialization
P0329R4: Designated Initialization
https://open-std.org/JTC1/SC22/WG14/www/docs/n494.pdf
https://en.cppreference.com/w/c/language/struct_initialization.html