Search code examples
c++aggregate-initialization

Inline member initialization with values of other aggregate initialized members


Is such code with the aggregate initialization a valid C++ program?

#include <iostream>
#include <numeric>

struct Sheet {
  const int c[2]{};
  const int sum = std::accumulate(std::begin(c), std::end(c), 0);
};

int main() {
  Sheet sheet0;
  Sheet sheet1{{10}};
  Sheet sheet2{{10, 20}};
  std::cout << sheet0.sum << "\n";
  std::cout << sheet1.sum << "\n";
  std::cout << sheet2.sum << "\n";
}

// Outputs:
// 0
// 10
// 30

This is a struct with the Excel sheet like behavior: a user initializes cells with some values, if a user does not initialize sum then it gets the computed sum of the cell values.

I am not sure that inline member initialization and not zero initialization happens at skipped members in aggregate initialization.

I expected that the statement

Sheet sheet2{{10, 20}};

would be the same as

Sheet sheet2{{10, 20}, {}};

and output 0, but my program runs showed that they result in different outputs 30 and 0.


Solution

  • For Sheet sheet2{{10, 20}};, the data member sum will be initialized by its default member initializer. It's not same as Sheet sheet2{{10, 20}, {}}; where sum will be initialized by {}.

    For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:

    • If the element has a default member initializer, the element is initialized from that initializer. (since C++11)

    • Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list.

    • Otherwise, the program is ill-formed.

      struct S
      {
          int a;
          const char* b;
          int c;
          int d = b[a];
      };
      
      // initializes ss.a with 1,
      //             ss.b with "asdf",
      //             ss.c with the value of an expression of the form int{} (that is, 0),
      //         and ss.d with the value of ss.b[ss.a] (that is, 's')
      S ss = {1, "asdf"};
      

    In detail, for Sheet sheet0;, data member c and sum will be initialized by their default member initializers. The 2 elements of c will be zero.

    For Sheet sheet1{{10}};, c will be initialized by {10}, sum will be initialized by its default member initializer. As {10} contains only 1 initializer which is less than the number of members of c as 2, the 1st element of c will be 10 and the 2nd one will be zero.

    For Sheet sheet2{{10, 20}};, c will be initialized by {10, 20}, sum will be initialized by its default member initializer. As the effect the 1st element of c will be 10 and the 2nd one will be 20.