Back to Blog
C C99 C++ C++20 Tips

Designated Initializers: Finally in C++20

7 min read
Progress 0/?

Designated initializers let you name the members of a struct during initialization in a way that’s checked by the compiler. To see why this is helpful, consider the following example where I accidentally swapped two parameters in the constructor:

Preventing bugs


#include <iostream>

struct Config {
    int timeout;
    int retries;
    bool verbose;
};

int main() {
    Config cfg{30, false, 1};
    std::cout << "Config: timeout=" << cfg.timeout 
              << ", retries=" << cfg.retries 
              << ", verbose=" << std::boolalpha << cfg.verbose << "\n";
    return 0;
}
Godbolt

Believe it or not, this compiles with no warnings on GCC 15.2! false is implicitly converted to 0, and 1 is implicitly converted to true, so the swapping of retries with verbose isn’t caught.


If we had written Config cfg{.timeout=30, .verbose=false, .retries=1}, the compiler would initialize the struct correctly or trigger a compilation error depending on whether we were in C or C++.

Basic Syntax

📝 Exercise 1: Basic Designated Initializers

Initialize the Person struct using designated initializers so it prints the expected output.

Try it ✓ Complete

Partial Initialization

We can also use designated initializers to do partial initialization:


#include <iostream>

struct Settings {
    int volume;           // guaranteed to be 0 if partially initialized
    int brightness = 100; // default value
    bool darkMode = true; // default value
};

int main() {
    // Only override brightness, keep defaults for others
    Settings s{.brightness = 75};
    
    std::cout << "Settings: volume=" << s.volume 
              << ", brightness=" << s.brightness 
              << ", darkMode=" << std::boolalpha << s.darkMode << "\n";
    return 0;
}
Godbolt

If a struct member doesn’t have a default, it’ll be zero-initialized.

📝 Exercise 2: Partial Initialization

Given the NetworkConfig struct with defaults, use designated initializers to set ONLY the port to 8080.

Try it ✓ Complete

Limitations

In C++ specifically, designated initializers must be written in order of the struct members. We also can’t use designated initialization with user-provided constructors, virtual base classes, or non-public member variables.

class Widget {
    int value;            // private - can't use designated init
public:
    Widget(int v);        // user-provided constructor
};

Widget w{.value = 42};    // Won't compile

struct Point {
    int x;
    int y;
};

Point p{.y = 2, .x = 1};  // Won't compile in C++, will compile in C

Fun in C

C’s designated initializers are more interesting. Aside from working in any order, nested initialization and array initialization are also acceptable.


#include <stdio.h>

struct Point {
    int x;
    int y;
};

struct Window {
    struct Point origin;
    int width;
    int height;
};

int main(void) {
    // Nested designated initializers - valid C, invalid C++
    struct Window w = {
        .origin.y = 7, // Out of order!
        .origin.x = 6,
        .width = 67,
        .height = 76
    };
    
    printf("Window: (%d, %d) size %dx%d\n", 
           w.origin.x, w.origin.y, w.width, w.height);

    // Array initialization
    int 🫲🥴🫱[10] = {[6] = 7}; // Unicode variable names????
    printf("🫲🥴🫱[6] = %d", 🫲🥴🫱[6]);

    return 0;
}
Godbolt

Let’s try C out!

📝 Exercise 3: C-style designated initialization

Use C's array designators to create a sparse array with specific values at indices 2, 5, and 9. Initialize them in whatever order you want.

Try it ✓ Complete

Got questions or cool use cases? Find me on LinkedIn!

JJ Marr

JJ Marr

SDE II @ AMD

Share: