I agree with @Nicol Bolas. MSVC and gcc are right while clang and icc are wrong.
In overloading resolution, list initialization differs from copy initialization that list initialization considers explicit constructors while copy initialization doesn't.
(From cppreference)
List-initialization When an object of non-aggregate class type T is
list-initialized, two-phase overload resolution takes place.
at phase 1, the candidate functions are all initializer-list
constructors of T and the argument list for the purpose of overload
resolution consists of a single initializer list argument if overload
resolution fails at phase 1, phase 2 is entered, where the candidate
functions are all constructors of T and the argument list for the
purpose of overload resolution consists of the individual elements of
the initializer list. If the initializer list is empty and T has a
default constructor, phase 1 is skipped.
In copy-list-initialization, if phase 2 selects an explicit
constructor, the initialization is ill-formed (as opposed to all over
copy-initializations where explicit constructors are not even
considered).
Some examples:
This one
#include <iostream>
#include <initializer_list>
struct A
{
explicit A(int, int, int) {}
};
struct B
{
B(std::initializer_list<int>) {}
};
void f(A) //f1
{
std::cout << 1 << std::endl;
}
void f(B) //f2
{
std::cout << 2 << std::endl;
}
int main()
{
f({ 1,2,3 }); //list initialziation
}
fails on MSVC and gcc. (See here and here)
This one
#include <iostream>
#include <initializer_list>
struct A
{
explicit A(std::initializer_list<int>) {}
};
struct B
{
B(std::initializer_list<int>) {}
};
void f(A) //f1
{
std::cout << 1 << std::endl;
}
void f(B) //f2
{
std::cout << 2 << std::endl;
}
int main()
{
f({ 1,2,3 }); //Also list initialization
}
also fails on MSVC and gcc. (See here and here)
While this one
#include <iostream>
#include <initializer_list>
struct A
{
explicit A(int) {}
};
struct B
{
B(int) {}
};
void f(A) //f1
{
std::cout << 1 << std::endl;
}
void f(B) //f2
{
std::cout << 2 << std::endl;
}
int main()
{
f(1); //Copy initialization
}
successes on all four compilers.