#include <iostream>
struct Data{};
struct Test{
Test() = default;
Test(Data){}
};
int main(){
Data d;
Test const& rf = d;
}
Consider the above code, The standard says:
Otherwise:
- 5.2.2.1 If T1 or T2 is a class type and T1 is not reference-related to T2, user-defined conversions are considered using the rules for copy-initialization of an object of type “cv1 T1” by user-defined conversion ([dcl.init], [over.match.copy], [over.match.conv]); the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed. The result of the call to the conversion function, as described for the non-reference copy-initialization, is then used to direct-initialize the reference. For this direct-initialization, user-defined conversions are not considered.
- 5.2.2.2 Otherwise, the initializer expression is implicitly converted to a prvalue of type “cv1 T1”. The temporary materialization conversion is applied and the reference is bound to the result.
So, which bullet does the above case obey? The initializer expression is converted to type Test through converting constructor Test::Test(Data) rather than conversion function. However note the emphasized part in 5.2.2.1, It says that the result of the call to the conversion function is then used to direct-initialize the reference. In my example, the called function was converting constructor, hence, the resulting was resulted from converting constructor.
Issue 1:
which bullet covers my example? 5.2.2.1 or 5.2.2.2?
5.2.1.2 has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be converted to an rvalue or function lvalue of type “cv3 T3”, where “cv1 T1” is reference-compatible with “cv3 T3” (see [over.match.ref]),
Consider the bullet 5.2.1.2, It has already covered the case which type T2 is a class type, and it can be converted to cv3 T3 through conversion function.
Issue 2:
So, Is it redundant that 5.2.2.1 covers T2 is a class type, and it can be converted to destination type through conversion function, Such case has already covered in 5.2.1.2?
Issue 1
[dcl.init.ref]/5.2.2.1 applies here. It is the paragraph covering user-defined conversions. One of the acceptable conversion mechanisms is 16.3.1.4 [over.match.copy] which can use converting constructors on
T1. The value is converted using this constructor and the resulting temporary is bound to the reference.[dcl.init.ref]/5.2.2.2 applies to cases of implicit conversion not including user-defined conversion, such as widening numeric conversions.
Issue 2
From [dcl.init.ref]:
Jumping to 16.3.1.6 [over.match.ref], there is a lot of prose here, but this is the only relevant part:
The rest of the section details which conversion functions of
Sare eligible to be used, but that's unimportant to the situation in the example code. [over.match.ref] considers only conversion operators on the type of the value being used to initialize the reference, which would not be the case here --Datahas no implicit conversion operators. This section makes no reference to converting constructors ofT.Therefore [over.match.ref] and by extension [dcl.init.ref]/5.2.1.2 do not apply to this case.