Hi!
I was reading the spec and found that it appears to apply a "wording trick" here, to make a function viable but render the call illformed (as we know from several other cases, for example with lvalue references to bitfield, yet there the trick is more obvious):
"[
Note 1:
Aggregate initialization does not require that
the members are declared in designation order
. If, after overload resolution, the order does not match
for the selected overload,
the initialization of the parameter will be ill-formed (
[dcl.init.list])
."
(this follows from the normative wording for the simple non-nesting case.. I take the note because it clears the air here and shows the intention).
However, as [dcl.init.aggr] notes (and again it follows from the normative wording anyway), if a member is initialized by {...} again, then the rules of list initialization applies. Therefore I think that [dcl.init.aggr] applies constraints on the order of members indirectly:
"[
Note 3:
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]"
I take all this to mean that the nested case is to be treated differently than the non-nested case, if going by the letter of the spec, but the implementations I tried (gcc and clang) treat the followinig example as being ambiguous, rather than selecting "C<B>":
struct A {
int x; int y;
};
struct B {
int y; int x;
};
template<typename T>
struct C {
T a;
};
void f(C<A> a);
void f(C<B> b);
int main() {
f({{ .y = 1, .x = 2}});
}