C++20 introduces Designated Initializers, which let you initialize struct or array members by name instead of position. This improves clarity and allows values to be set in any order. The feature works with specific aggregate (collection) types that follow simple structural rules.
- Members can be initialized out of order, making code easier to read and maintain.
- Only supported for aggregate types without custom constructors, virtual functions, or restricted-access members.
- Helps avoid mistakes caused by relying only on positional initialization.
#include <iostream>
using namespace std;
// Create Structure
struct Date {
int year;
int month;
int day;
};
int main()
{
Date dt{ .year = 2023, .month = 4, .day = 24 };
cout << "Year : " << dt.year << "\n";
cout << "Month : " << dt.month << "\n";
cout << "Day : " << dt.day;
return 0;
}
Output
Year : 2023 Month : 4 Day : 24
Syntax
struct_type obj_name = {
.member1 = value1, .member2 = value2, member3 = value3, ...... .memberN = valueN
};
Where,
- struct_type: The name of the struct type.
- obj_name: The name of the object being initialized.
- member1 to memberN: The names of the data members being initialized.
- value1 to valueN: The values being assigned to the corresponding data members.
- We use the dot operator (.) followed by the member name to specify the member we want to initialize.
#include <iostream>
using namespace std;
struct Date {
int month;
int year;
};
int main()
{
// dt.month = 4, dt.year = 2023
Date dt{ 4, 2023 };
cout << "Month : " << dt.month << "\n";
cout << "Year : " << dt.year << "\n";
return 0;
}
Output
Month : 4 Year : 2023
Now, imagine if we were to update the struct definition by adding a new member, which is not the last member.
#include <iostream>
using namespace std;
struct Date {
int day;
int month;
int year;
};
int main()
{
// dt.day = 4, dt.month = 2023, dt.year = 0
Date dt{ 4, 2023 };
cout << "Month : " << dt.month << "\n";
cout << "Year : " << dt.year << "\n";
cout << "Day : " << dt.day;
return 0;
}
Output
Month : 2023 Year : 0 Day : 4
However, with Designated Initializers, we can simply add the new member and update its value without affecting initialization code. This can save time and effort while also reducing the chances of introducing bugs due to human error.
Initializing with Designated Initializers
#include <iostream>
using namespace std;
struct Date {
int day;
int month;
int year;
};
int main()
{
Date dt{ .day = 24, .month = 4, .year = 2023 }; // dt.day = 24, dt.month = 4, dt.year = 2023
cout << "Month : " << dt.month << "\n";
cout << "Year : " << dt.year << "\n";
cout << "Day : " << dt.day;
return 0;
}
Output
Month : 4 Year : 2023 Day : 24
Advantages of Designated Initializers
- Readability and Maintainability: By using designated initializers, it's easy to understand which member is being initialized with what value, even if the struct has many members.
- Partial or Subset Initialization: It allows us to initialize only a subset of members in the struct. This can be useful when we don't want to initialize all members of the strict or when we only need to initialize a few members.
- Flexible Initialization: It allows us to initialize the members of a struct or array in any order we want. This can be useful when we want to initialize the members in a specific order or when we want to group related members together.
- Nested Structs and Arrays: Designated Initializers can also be used to initialize nested structs or Arrays, making the initialization of complex data structures more straightforward and easier to read. It can also reduce the amount of boilerplate code required for initialization, as we can directly specify the values for each member instead of creating temporary variables or using multiple assignment statements.