https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92385

--- Comment #6 from Carl <edquist at cs dot wisc.edu> ---
> I'm not sure if () and {} are semantically equivalent [in this case].

For what it's worth, (not sure if I'm allowed to paste a link here, but) on
cppreference.com [1] under "Constructors and member initializer lists", it
describes the following forms for "member-initializers" in "the body of a
function definition of any constructor" :

    class-or-identifier ( expression-list(optional) )   (1)     
    class-or-identifier brace-init-list                 (2) (since C++11)

And about these it says:

    1) Initializes the base or member named by class-or-identifier
       using direct initialization or, if expression-list is empty,
       value-initialization

    2) Initializes the base or member named by class-or-identifier
       using list-initialization (which becomes value-initialization
       if the list is empty and aggregate-initialization when
       initializing an aggregate)

So it seems in this case of "a()" (1) vs "a{}" (2), either one results in
"value-initialization", which is further described here [2].

The following forms are described for value-initialization:

    T()  (1)
    T{}  (5)  (since C++11)

About which it says:

    1,5) when a nameless temporary object is created with the
         initializer consisting of an empty pair of parentheses
         [or braces (since C++11)];

But then it goes on to say:

    In all cases, if the empty pair of braces {} is used and T is
    an aggregate type, aggregate-initialization is performed instead
    of value-initialization.

(And notably, an array is an aggregate type.)

Then the page on aggregate-initialization[3] goes on to describe the many
semantic effects of aggregate initialization...  The part that seems to apply
is

    If the number of initializer clauses is less than the number
    of members or initializer list is completely empty, the
    remaining members are initialized by empty lists, in accordance
    with the usual list-initialization rules (which performs
    value-initialization for non-class types and non-aggregate
    classes with default constructors, and aggregate initialization
    for aggregates).   (since C++11)


I presume our "struct item" counts as a "non-aggregate class with default
constructor", which would result in value-initialization, but my lawyer glasses
are a little fuzzy here.


Whereas, the way I read the value-initialization rules, if "()" is used (that
is, not "the empty pair of braces {}"), then this rule applies:

    3) if T is an array type, each element of the array is
       value-initialized;

Which means that for every element of the array this applies:

    1) if T is a class type with [...] a user-provided [...] constructor,
       the object is default-initialized;


So, a bit round-about, but it seems like both routes would result in
value-initialization, which ends up meaning each element gets
default-initialized.

But you have to squint real hard, and the rules about how to get there seem to
follow surprisingly different-looking paths...  Maybe that (partially) explains
the different code-paths in g++.

Carl


[1] https://en.cppreference.com/w/cpp/language/initializer_list
[2] https://en.cppreference.com/w/cpp/language/value_initialization
[3] https://en.cppreference.com/w/cpp/language/aggregate_initialization

Reply via email to