List, Aggregate, and Designated Initialization

Designated Initializers with Private Members

Can designated initializers be used with types that have private or protected members?

Abstract art representing computer programming

Designated initializers, introduced in C++20, are a convenient way to initialize objects by specifying the member names. However, they can only be used with aggregate types, which do not include private or protected members.

Let's consider an example with an aggregate type:

#include <iostream>

struct Vec3 {
  int x{0};
  int y{0};
  int z{0};
};

int main() {
  Vec3 vector{.x = 1, .y = 2, .z = 3};  
  std::cout << "x=" << vector.x
    << ", y=" << vector.y
    << ", z=" << vector.z;
}
x=1, y=2, z=3

In this case, Vec3 is an aggregate type because it has no private members, non-public base classes, or user-defined constructors. This allows us to use designated initializers to initialize its members.

However, if Vec3 had private or protected members, it would no longer be considered an aggregate, and designated initializers would not work:

#include <iostream>

struct Vec3 {
private:
  int x{0};
  int y{0};
  int z{0};

public:
  Vec3(int a, int b, int c)
    : x{a}, y{b}, z{c} {}

  void Log() {
    std::cout << "x=" << x
      << ", y=" << y
      << ", z=" << z << '\n';
  }
};

int main() {
  Vec3 vector{.x = 1, .y = 2, .z = 3}; 
  vector.Log();
}
error: 'Vec3': designated initialization can only be used to initialize aggregate class types

This code will not compile because Vec3 is no longer an aggregate type due to the private members. Designated initializers cannot be used in this scenario.

To initialize types with private or protected members, you must use constructors. Constructors allow you to control how the members are initialized and can enforce encapsulation rules.

Here is how you can modify the Vec3 struct to use a constructor instead:

#include <iostream>

struct Vec3 {
 private:
  int x{0};
  int y{0};
  int z{0};

 public:
  Vec3(int a, int b, int c)
    : x{a}, y{b}, z{c} {}

  void Log() {
    std::cout << "x=" << x
      << ", y=" << y
      << ", z=" << z;
  }
};

int main() {
  Vec3 vector{1, 2, 3};  
  vector.Log();
}
x=1, y=2, z=3

In summary, designated initializers are great for aggregate types but cannot be used with types that have private or protected members. For such types, constructors are the appropriate way to handle initialization.

This Question is from the Lesson:

List, Aggregate, and Designated Initialization

A quick guide to creating objects using lists, including std::initializer_list, aggregate and designated initialization

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

List, Aggregate, and Designated Initialization

A quick guide to creating objects using lists, including std::initializer_list, aggregate and designated initialization

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved