Question Details

No question body available.

Tags

c++ language-lawyer c++20

Answers (1)

Accepted Answer Available
Accepted Answer
January 3, 2026 Score: 5 Rep: 2,703 Quality: High Completeness: 80%

Initializers in a designated-initializer-list are governed by the same rules as those appearing in other contexts, thus the code in question can be simplified to:

template
struct B {
    B(T);

operator T();

template operator B(); };

B myb(42);

// OK everywhere B b0 = myb;

// Error on MSVC B b1(myb); B b2 {myb};

// Error on GCC/MSVC B b3 = {myb};

(GCC accepts b2 above but rejects the equivalent initializer in the context of aggregate initialization, as in the OP.)

For the last three cases, [dcl.init.general]/16.6.2 and [dcl.init.list]/3.7 specify that overload resolution is performed among the constructors of B to perform the initialization. There are three viable candidates (B(double), and the implicitly declared copy/move constructors), all requiring a user-defined conversion to be applied to myb (using B::operator int for the former, B::operator B for the latter). According to [over.ics.rank]/3.3, two user-defined conversion sequences can only be ranked if they use the same conversion function, leading to an ambiguity here.

The form of initialization used for b0 is special, however, because it considers the constructors of B and the conversion function B::operator B as part of a single candidate set ([dcl.init.general]/16.6.3). The conversion function is unambiguously better than every constructor, requiring no conversions at all to initialize its (implicit) parameter from my_b, and is therefore selected to initialize the b0 object.

In conclusion, the behavior of MSVC aligns most closely with the standard here.