# Designated Initializers

Contents[Show]

Designated initialization is an extension of aggregate initialization and empowers you to directly initialize the members of a class type using their names. Designated initialization is a special case of aggregate initialization. Writing about designated initialization means, therefore, to write about aggregate initialization.

## Aggregate Initialization

First: what is an aggregate. Aggregates are arrays and class types. A class type is a class, a struct, or a union.

With C++20, the following condition must hold class types:

• no private or protected non-static data members
• no user-declared or inherited constructors
• no virtual, private, or protected base classes
• no virtual member functions

The next program exemplifies aggregate initialization.

```// aggregateInitialization.cpp

#include <iostream>

struct Point2D{
int x;
int y;
};

class Point3D{
public:
int x;
int y;
int z;
};

int main(){

std::cout << std::endl;

Point2D point2D{1, 2};        // (1)
Point3D point3D{1, 2, 3};     // (2)

std::cout << "point2D: " << point2D.x << " " << point2D.y << std::endl;
std::cout << "point3D: " << point3D.x << " " << point3D.y << " " << point3D.z << std::endl;

std::cout << std::endl;

}
```

(1) and (2) directly initializes the aggregates using curly braces. The sequence of the initializers in the curly braces have to match the declaration order of the members. Based on aggregate initialization in C++11, we get designed initializers in C++20. So far, only the Microsoft compiler support designated initializers completely.

## Designated Initializers

Designated initializers enable it to directly initialize members of a class type using their name. For a union, only one initializer can be provided. As for aggregate initialization, the sequence of initializers in the curly braces have to match the declaration order of the members.

```// designatedInitializer.cpp

#include <iostream>

struct Point2D{
int x;
int y;
};

class Point3D{
public:
int x;
int y;
int z;
};

int main(){

std::cout << std::endl;

Point2D point2D{.x = 1, .y = 2};          // (1)
Point3D point3D{.x = 1, .y = 2, .z = 3};  // (2)

std::cout << "point2D: " << point2D.x << " " << point2D.y << std::endl;
std::cout << "point3D: " << point3D.x << " " << point3D.y << " " << point3D.z << std::endl;

std::cout << std::endl;

}
```

(1) and (2) use designated initializers to initialize the aggregates. The initializers such as .x or .y are often called designators. The members of the aggregate can already have a default value. This default value is used when the initializer is missing. This does not hold for a union.

```// designatedInitializersDefaults.cpp

#include <iostream>

class Point3D{
public:
int x;
int y = 1;
int z = 2;
};

void needPoint(Point3D p) {
std::cout << "p: " << p.x << " " << p.y << " " << p.z << std::endl;
}

int main(){

std::cout << std::endl;

Point3D point1{.x = 0, .y = 1, .z = 2};     // (1)
std::cout << "point1: " << point1.x << " " << point1.y << " " << point1.z << std::endl;

Point3D point2;                             // (2)
std::cout << "point2: " << point2.x << " " << point2.y << " " << point2.z << std::endl;

Point3D point3{.x = 0, .z = 20};            // (3)
std::cout << "point3: " << point3.x << " " << point3.y << " " << point3.z << std::endl;

// Point3D point4{.z = 20, .y = 1}; ERROR   // (4)

needPoint({.x = 0});                        // (5)

std::cout << std::endl;

}
```

(1) initializes all members,  but (2) does not provide a value for the member x. Consequently, x is  not initialized. It is fine if you only initialize the members who don't have a default value such as in (3) or (5). The expression (4) would not compile because z and y are in the wrong order. Designated initializers detect narrowing conversion. Narrowing conversion is a conversion of a value including the loss of its precision.

```// designatedInitializerNarrowingConversion.cpp

#include <iostream>

struct Point2D{
int x;
int y;
};

class Point3D{
public:
int x;
int y;
int z;
};

int main(){

std::cout << std::endl;

Point2D point2D{.x = 1, .y = 2.5};            // (1)
Point3D point3D{.x = 1, .y = 2, .z = 3.5f};   // (2)

std::cout << "point2D: " << point2D.x << " " << point2D.y << std::endl;
std::cout << "point3D: " << point3D.x << " " << point3D.y << " " << point3D.z << std::endl;

std::cout << std::endl;

}
```

(1) and (2) produce a compile-time error because the initialization .y = 2.5 and .z = 3.5f would cause a narrowing conversion to in. Interestingly, designated initializers in C behave differently to designated initializers in C++.

### Differences between C and C++

C supports use-cases that are not supported in C++. C allows

• to initialize the members of the aggregate out-of-order
• to initialize the members of a nested aggregate
• to mix designated initializers and regular initializers
• designated initialization of arrays

The proposal P0329R4 provides self-explanatory examples for these use-cases:

```struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // valid C, invalid C++ (out of order)
int arr = { = 5};        // valid C, invalid C++ (array)
struct B b = {.a.x = 0};       // valid C, invalid C++ (nested)
struct A a = {.x = 1, 2};      // valid C, invalid C++ (mixed)
```

The rational for this difference between C and C++ is also part of the proposal: "In C++, members are destroyed in reverse construction order and the elements of an initializer list are evaluated in lexical order, so field initializers must be specified in order. Array designators conflict with ​lambda-expression​ syntax. Nested designators are seldom used." The paper continues to argue, that only out-of-order initialization of aggregate is commonly used.

## What's next?

Wow! With C++98 we got const, with C++11 constexpr, and with C++20 consteval and constinit.  In my next post, I write about the new C++20 specifiers consteval and constinit and about their differences to const and constexpr

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Darshan Mody, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, espkk, Wolfgang Gärtner,  Louis St-Amour, Stephan Roslen, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Avi Kohn, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, and Peter Ware.

Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, and Embarcadero Marketing.

## Seminars

I'm happy to give online-seminars or face-to-face seminars world-wide. Please call me if you have any questions.

### Standard Seminars

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

### Modernes C++, 0 #1 Jonathan OConnor 2020-07-09 08:49
Rainer, what happens if Point2 has a constructor, default or non-copy, non-move? Does that disable the use of designated initializers, or can you always use designated initializers, so long as the members are visible at the point of instantiation?
0 #2 Rainer Grimm 2020-07-10 20:01
Quoting Jonathan OConnor:
Rainer, what happens if Point2 has a constructor, default or non-copy, non-move? Does that disable the use of designated initializers, or can you always use designated initializers, so long as the members are visible at the point of instantiation?

Hello Jonathan,
what a Aggregate is depends on the C++ version (https://en.cppreference.com/w/cpp/language/aggregate_initialization). With C++20 the requirements are quite weak regarding your question: no user-declared or inherited constructors
0 #3 Jonathan OConnor 2020-07-15 13:36
Rainer, I tried it out on Godbolt, and answered my own question (which was probably not phrased very clearly!). If a struct has any constructors, then you can't initialize an instance using designated initializers.

Example here: https://godbolt.org/z/K9doxx

### Subscribe to the newsletter (+ pdf bundle)

 Name Email Please enable the javascript to submit this form

### Visitors

Today 38675

Yesterday 8369

Week 55728

Month 222562

All 5519666

Currently are 274 guests and no members online

• #### Latches in C++20

Similar to sync.WaitGroup in golang: https://gobyexample.com/waitgroups In Go, the number of waiting ...

• #### C++ Core Guidelines: Passing Smart Pointers

I kind of find myself concurring with Yoed (comment #2) — unless the code in question is being run ...

• #### C++ Core Guidelines: Be Aware of the Traps of Condition Variables

Lost wakeups? I believe this is largely moot. Your critical section protects some place where you ...

• #### Semaphores in C++20

What's the implementation in the kernel that makes semaphores so fast, compared with atomic ...

• #### C++ Core Guidelines: Concurrency and lock-free Programming

I just want to let you know that I just check out your site and I find it very interesting and ...
{"ft_lang_label":"__label__en","ft_lang_prob":0.78091437,"math_prob":0.90822756,"size":7079,"snap":"2021-04-2021-17","text_gpt3_token_len":1993,"char_repetition_ratio":0.1923675,"word_repetition_ratio":0.20764552,"special_character_ratio":0.30244386,"punctuation_ratio":0.24476987,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.96172315,"pos_list":[0,1,2,3,4,5,6,7,8,9,10,11,12],"im_url_duplicate_count":[null,1,null,1,null,1,null,1,null,1,null,null,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2021-01-27T20:38:43Z\",\"WARC-Record-ID\":\"<urn:uuid:76441ef5-4f51-44aa-8129-7ba608603431>\",\"Content-Length\":\"136379\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:9748d30a-b9aa-4bb2-bd64-3ff5faf4aa11>\",\"WARC-Concurrent-To\":\"<urn:uuid:ec94e704-9d5e-42b4-9546-e86f122ede60>\",\"WARC-IP-Address\":\"81.169.145.80\",\"WARC-Target-URI\":\"http://modernescpp.com/index.php/designated-initializers\",\"WARC-Payload-Digest\":\"sha1:SEATF3ZIPK4OSFFUILJF2T2NDEMGYXMZ\",\"WARC-Block-Digest\":\"sha1:L5N3B2K2OKDFMEUCLWI7UNFU5ZADPGR4\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2021/CC-MAIN-2021-04/CC-MAIN-2021-04_segments_1610704832583.88_warc_CC-MAIN-20210127183317-20210127213317-00708.warc.gz\"}"}