This appears to be a bug clang(see it live) and gcc(see it live) accept this program and choose the std::initializer_list overload which looks correct since that is an exact match, this is covered in the C++ draft standard section section 13.3.3.1.5
List-initialization sequence paragraph 2 from the example:
void f(std::initializer_list<int>);
f( {1,2,3} ); // OK: f(initializer_list<int>) identity conversion
f( {’a’,’b’} ); // OK: f(initializer_list<int>) integral promotion
f( {1.0} ); // error: narrowing
we have an identity conversion which is an exact match.
For the reference overloads we go to paragraph 5 it says (emphasis mine going forward):
Otherwise, if the parameter is a reference, see 13.3.3.1.4. [ Note: The rules in this section will apply for initializing the underlying temporary for the reference. —end note ]
indicates that temporary is created an then we can apply the rules to resulting temporary. This will be a User-defined conversion which is worse than an exact match.
So this should not be ambiguous.
Update
Looks like there are two active bugs related to this: