Forwarding to an Aggregate Initializer?

For what it's worth, P0960 "Allow initializing aggregates from a parenthesized list of values" does exactly what it says. It seems to have passed EWG and is on its way into C++20.

aggregate types by definition have no other constructor to make the resolution ambiguous

That is incorrect. All classes have default constructors, as well as copy/move constructors. Even if you = delete them or they are implicitly deleted, they still technically have such constructors (you just can't call them).

C++ being C++, there are naturally corner cases where even P0960 does the "wrong thing", as outlined in the paper:

struct A;

struct C
{
  operator A(); //Implicitly convertible to `A`
};

struct A { C c; }; //First member is a `C`

C c2;
A a(c2);

The initialization of a is a case of ambiguity. Two things could happen. You could perform implicit conversion of c2 to an A, then initialize a from the resulting prvalue. Or you could perform aggregate initialization of a by a single value of type C.

P0960 takes the backwards compatible route: if a constructor could be called (under existing rules), then it always takes priority. Parentheses only invoke aggregate initialization if there is no constructor that could have been called.

Tags:

C++

C++17

C++20