I compile this code below with GCC 11.1.0 with a flag -std=c++17
. It occurs that on the stdout is printed initializer_list
.
I compiled the same code with MSVC with the flag -std=c++17
but it printed "copy constructor". Which compiler is more compliant with the cpp standard? Is compiler free to choose one of the constructors?
#include <iostream>
using namespace std;
struct S
{
S(int) { }
S(initializer_list<int>) { cout << "initializer_list"; }
S(const S&) { cout << "copy constructor"; }
operator int() const { return 1; };
};
int main()
{
S s1(20);
S s2{ s1 };
}
The compiler is pretty much never "free to choose" for stuff like this. If it were, we wouldn't be able to write pretty much any portable C++ code.
[over.match.list] does give priority to initializer_list
constructors. Constructor function overloading under the rules of list initialization gets invoked at step 3.6. Steps 3.1-3.5 do not apply, as your type doesn't qualify for any of those cases. Step 3.1 is particularly interesting, as it is specifically meant to invoke copy constructors instead of doing other things, but it also only applies to aggregates. Which your type is not.
Since your type is implicitly convertible to int
, and your type takes an initializer_list<int>
, there is a valid way to build an initializer_list
that matches a constructor for the type in question. Therefore, this is the constructor [over.match.list] will select.
So in this case, VC++ is wrong. As is Clang, apparently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With