Why is custom conversion applied during initialization?

The following code works fine:

#include <iostream> struct B { operator int() { return int(); } }; struct A { A(int, int){ std::cout << "A(int, int)" << std::endl; } }; A a({B(), B()}); int main() { } 

and displays the result:

 A(int, int) 

Demo

But I can’t understand why? What the standard says:

However, when considering a constructor argument or a user-defined conversion function that is a candidate according to 13.3.1.3, when the class instance is initialized for copying / moving in the second stage, according to 13.3.1.7, when passing the initializer, the list as one argument or when the list of initializers has exactly one element and conversion to some class X or a reference to (possibly cv-qualified) X is considered for the first constructor parameter from X [...] only standard sequences are considered conversion lengths and ellipsis conversion sequences

So, in our case, we considered the constructor argument (it was {B(), B()} ). More precisely, we passed the list of initializers as one argument (the second case in the specified rule). Now we need to convert the first element of the initializer list (temporary type B ) to int , and the only way to do this is to use a user-defined conversion ( B::operator int() ). But, as said at the end of the rule that I called , only standard conversion sequences and ellipsis sequences were considered . Since this code should not work, it should cause an error, since A(int, int) not viable or kind.

What happened. Maybe this is a mistake?

+5
source share
1 answer

The text was faulty and modified using C ++ 14. Now [over.best.ics] / 4 reads

However, if the goal

  • first constructor parameter or
  • [...]

and the constructor or custom transform function is a candidate for

  • 13.3.1.3, when the argument is temporary in the second step of initializing the class instance ,
  • 13.3.1.4, 13.3.1.5 or 13.3.1.6 (in all cases) or
  • the second phase 13.3.1.7, when the list of initializers has exactly one element, and the target is the first parameter of the constructor of class X , and the conversion is X or a link to (possibly with qualification cv) X ,

custom conversion sequences are not considered. [Note: these rules prevent more than one user-defined transform from being applied during overload resolution, thereby avoiding infinite recursion. - end note]

Converting B() to int does not apply to this - the bold phrase only refers to binding the temporary reference during copy initialization.
However, Clang rejects this sample code in accordance with the above:

 class A; struct B { operator A(); }; struct A { A(A const&){} }; A a{B()}; 
+1
source

Source: https://habr.com/ru/post/1208067/


All Articles