Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`auto x = type{...}` initialization syntax and `explicit` conversion operator - clang vs gcc

Given this code (on wandbox):

struct X
{
    explicit operator int() { return 0; }
};

int main()
{
    auto y = int{X{}};
}

And the following compiler options:

-std=c++1z -Wall -Wextra -Wpedantic


  • g++ (tested versions: 7, 6.1, 5.3) refuses to compile the code with the following error

    error: cannot convert 'X' to 'int' in initialization

  • clang++ (tested versions: 4, 3.8, 3.6) happily compiles the snippet.


Which compiler is doing the correct thing here?

cppreference seems to suggest that the auto var = type{...} syntax should trigger an explicit conversion.

like image 957
Vittorio Romeo Avatar asked Oct 13 '16 10:10

Vittorio Romeo


1 Answers

Using http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/n4606.pdf I think g++ is wrong.

8.6.4 clause 3.7 states:

— Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); if a narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.

Meaning that direct init is used in this case of non-class type, which leads us to 8.6 clause 17.7:

— Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into the object being initialized. If the conversion cannot be done or is ambiguous, the initialization is ill-formed.

And finally 13.3.1.5 states that both explicit and implicit conversions are considered for direct initialization:

— The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T with a qualification conversion (4.5) are also candidate functions. Conversion functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type for this process of selecting candidate functions. Conversion functions that return “reference to cv2 X” return lvalues or xvalues, depending on the type of reference, of type “cv2 X” and are therefore considered to yield X for this process of selecting candidate functions.

like image 110
Sergey Murzin Avatar answered Oct 13 '22 00:10

Sergey Murzin