What are the rules of field-by-field constructor generation?
Asked Answered
C

3

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?

Corselet answered 29/6, 2016 at 12:24 Comment(0)
V
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.

Vinna answered 29/6, 2016 at 12:28 Comment(0)
H
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.
Homeless answered 29/6, 2016 at 12:28 Comment(2)
thank you very much. I use MSVC++ 2013, and it's the problem.Corselet
The question was tagged c++11, though, and this doesn't explain why the version matters.Valerlan
S
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).

Schofield answered 30/6, 2016 at 9:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.