This is a GCC bug.
First, braces around scalar initializer (list-initialization for scalar type) are permitted according to [dcl.init.list]/3.9:
Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); if a narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.
[ Example:
int x1 {2}; // OK
int x2 {2.0}; // error: narrowing
— end example ]
Second, Node<int>
is an aggregate according to [dcl.init.aggr]/1:
An aggregate is an array or a class with
no user-provided, explicit, or inherited constructors ([class.ctor]),
no private or protected non-static data members ([class.access]),
no virtual functions, and
no virtual, private, or protected base classes ([class.mi]).
So aggregate initialization is performed and val
is list-initialized with {args...}
recursively according to [dcl.init.aggr]/4.2:
Otherwise, the element is copy-initialized from the corresponding initializer-clause or the brace-or-equal-initializer of the corresponding designated-initializer-clause. If that initializer is of the form assignment-expression or = assignment-expression and a narrowing conversion is required to convert the expression, the program is ill-formed. [ Note: If an initializer is itself an initializer list, the element is list-initialized, which will result in a recursive application of the rules in this subclause if the element is an aggregate. — end note ]
Then [dcl.init.list]/3.9 applies again.
As a conclusion, this initialization is well-defined.
{args...}
solves the problem for GCC and Clang. – Arnav Borborahreturn {nullptr, args... };
– Richard Crittenstruct { int x; } v = { {1} };
though it does allowint x = {1};
. I think it's a bug of GCC. – cpplearner