2

In my use case I needed to initialize a class variable using an initializer list. I learnt that an aggregate class is a class that just has user defined data members in it.

The advantage of aggregate is that we can use initializer list like this

struct fileJobPair {
        int file;
        int job;
};

fileJobPair obj = {10, 20};

But if I add a constructor to it, the class no longer remains an aggregate

struct fileJobPair {
        int file;
        int job;
        fileJobPair() {
            file = job = 0;
        }
        fileJobPair(int a, int b) {
            file = a;
            job = b;
        }
};

But I see that the initializer list advantage that we had for aggregate classes can still be used over here.

fileJobPair obj = {10, 20};

So my question is why do we even need an aggregate if the same thing can be acieved by regular class. What are the advantages and real life use case of aggregates.

1 Answers1

1

What are the advantages <...> of aggregates

Unlike "usual" classes, aggregate types:

  1. have pre-defined "constructor" (your example)
  2. need no tuple-like interface boilerplate for structured bindings:
struct { int field1, field2; } aggregate;
auto&& [_1, _2] = aggregate;
  1. have designated initializers:
Aggregate{.something = 42, .something_else = "whatever"};

Maybe there's something else I didn't think about.

What are the <...> real life use case of aggregates

E.g. you can (de)serialize them with no boilerplate thanks to #2, see also Boost.PFR. You can easily merge them (like tuples), "foreach" their fields etc.

An example for #3: replace tons of the Builder pattern code with

struct Foo {
  struct Builder { std::string_view a, b, c; };
  constexpr Foo(Builder); // TODO
} example{{.a = "cannot set a field twice", .c = "can skip fields"}};

the same thing can be acieved by regular class

As you can see, it either cannot or requires extra boilerplate.

passing_through
  • 1,778
  • 12
  • 24