16

I have found that the possibility of usage of initializer list syntax for a class depends on whether or not the class fields have default values. Why?

To be precise, consider the following code:

class S
{
    public:
        int a;
};
...
int a;
S s{ a };

It compiles without any problems. But if I add a default value to the class field, it stops building:

class S
{
    public:
        int a = 0;
};
...
int a;
S s{ a };

Error 1 error C2440: 'initializing' : cannot convert from 'initializer-list' to 'S'

Why? What else influences such constructor generation?

zajonc
  • 1,935
  • 5
  • 20
  • 25
alexeykuzmin0
  • 6,344
  • 2
  • 28
  • 51

3 Answers3

19

In C++14, your code is valid and should compile with any C++14 compatible compiler.


In C++11 however:

If you do not have a default value for a, your type is an aggregate, and thus aggregate initialization can be performed:

An aggregate is one of the following types:

  • array type

  • class type (typically, struct or union), that has

    • no private or protected non-static data members
    • no user-provided constructors , including those inherited from public bases (since C++17) (explicitly defaulted or deleted constructors are allowed) (since C++11)
    • no virtual, private, or protected (since C++17) base classes
    • no virtual member functions
    • no default member initializers (since C++11, until C++14)

As soon as you add a default value for the attribute a, your aggregate initialization cannot be performed anymore since your type stop being an aggregate.

skypjack
  • 49,335
  • 19
  • 95
  • 187
Holt
  • 36,600
  • 7
  • 92
  • 139
4

The shown code compiles without any issues with gcc 6.1.1. You're likely using an older compiler that does not fully support C++14:

$ cat t.C
class S
{
public:
  int a = 0;
};


void foo()
{
    int a=4;

    S s{a};
}
$ g++ -std=c++1z -g -c -o t.o t.C
$ g++ --version
g++ (GCC) 6.1.1 20160510 (Red Hat 6.1.1-2)
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
2

In both cases the default constructor of S takes no arguments. The form of the class does not affect the generation of the default constructor. Further, there is no implicitly-generated constructor taking int.

If S is an aggregate, then the usage S s = { arguments_opt }; does not invoke S's constructor. Instead it invokes something called aggregate initialization. Aggregates are the only classes such that objects of that class can be created without a constructor invocation.

Only if S is not an aggregate, does S s = { arguments_opt }; try to match the argument list to the parameters of a constructor of S.

(As explained by others, in C++11, providing a brace-or-equal-initializer for a non-static data member makes the class not be an aggregate).

M.M
  • 138,810
  • 21
  • 208
  • 365