This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-11-11
[Voted into the WP at the March, 2009 meeting.]
11.4.8.3 [class.conv.fct] paragraph 1 says,
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.
At what point is this enforced, and how is it enforced?
Consider this test case:
struct abc; struct xyz { xyz(); xyz(xyz &); operator xyz& (); // #1 operator abc& (); // #2 }; struct abc : xyz {}; void foo(xyz &); void bar() { foo (xyz ()); }
If such conversion functions are part of the overload set, #1 is a better conversion than #2 to convert the temporary xyz object to a non-const reference required for foo's operand. If such conversion functions are not part of the overload set, then #2 would be selected, and AFAICT the program would be well formed.
If the conversion functions are not part of the overload set, then it would seem one cannot take their address. For instance, adding the following line to the above test case would find no suitable function:
xyz &(xyz::*ptr) () = &xyz::operator xyz &;
Notes from the October, 2007 meeting:
The intent of 11.4.8.3 [class.conv.fct] paragraph 1 is that overload resolution not be attempted at all for the listed cases; that is, if the target type is void, the object's type, or a base of the object's type, the conversion is done directly without considering any conversion functions. Consequently, the questions about whether the conversion function is part of the overload set or not are moot. The wording will be changed to make this clearer.
Proposed Resolution (October, 2007):
Change the footnote in 11.4.8.3 [class.conv.fct] paragraph 1 as follows:
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void. [Footnote: These conversions are considered as standard conversions for the purposes of overload resolution (12.2.4.2 [over.best.ics], 12.2.4.2.5 [over.ics.ref]) and therefore initialization (9.4 [dcl.init]) and explicit casts (7.6.1.9 [expr.static.cast]). A conversion to void does not invoke any conversion function (7.6.1.9 [expr.static.cast]). Even though never directly called to perform a conversion, such conversion functions can be declared and can potentially be reached through a call to a virtual conversion function in a base class —end footnote]
Additional note (March, 2008):
A slight change to the example above indicates that there is a need for a normative change as well as the clarification of the rationale in the October, 2007 proposed resolution. If the declaration of foo were changed to
void foo(const xyz&);
with the current wording, the call foo(xyz()) would be interpreted as foo(xyz().operator abc&()) instead of binding the parameter directly to the rvalue, which is clearly wrong.
Proposed resolution (March, 2008):
Change the footnote in 11.4.8.3 [class.conv.fct] paragraph 1 as described in the October, 2007 proposed resolution.
Change 9.4.4 [dcl.init.ref] paragraph 5 as follows:
A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
If the initializer expression
is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or
has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an lvalue of type “cv3 T3,” where “cv1 T1” is reference-compatible with “cv3 T3” [Footnote: This requires a conversion function (11.4.8.3 [class.conv.fct]) returning a reference type. —end footnote] (this conversion is selected by enumerating the applicable conversion functions (12.2.2.7 [over.match.ref]) and choosing the best one through overload resolution (12.2 [over.match])),
then...
[Drafting note: this resolution makes the example in the issue description ill-formed.]