The difference can be reduced to
struct A { explicit A(int); };
struct B { B(int); };
void f(A);
void f(B);
int main() {
f({ 1 });
}
On GCC this fails, in accordance to the Standard (which says that for list initialization, explicit constructors are considered - so they can yield an ambiguity - but they just are not allowed to be selected). Clang accepts it and calls the second function.
In your case, what @Columbo says in his answer to Direct list initialization compiles successfully, but normal direct initialization fails, why? applies. With the difference that in your case, B(const B&);
is not anymore acceptable to Clang because the {0} -> B
conversion would be faced with two possibilities: the explicit constructor or using the copy constructor recursively a second time. The first option, as explained above, will not be considered by clang and this time the explanation by @Columbo applies and the copy constructor cannot be used a second time because that would need a user defined conversion as we have a single element (here, 0
). So in the summary, only the first constructor succeeds and is taken.
Since I understand the issue is about weird overload resolution rules and some might not be able to follow, here's a more intuitive explanation. The rules that are active are, in order
Therefore for GCC it can use the explicit constructor directly, and in addition by a single use of the copy constructor. For clang, it only considers using the explicit constructor directly, and it won't use it indirectly by a copy-list-initialization using the copy constructor like GCC does. Both won't consider using the copy constructor a second time, and it's irrelevant here.