"explicit" for Operator Conversion Functions X3J16/95-0046 WG21/N0646 Gavin Koch sasgak@unx.sas.com As discussed in Valley Forge, this paper proposes that the "explicit" keyword be allowed on all user defined conversions (not just constructors). This proposal also attempts to clarify some issues with regard to the explicit keyword as used on constructors. The first part of this paper describes the intent of the proposal, the second part is my attempt at the necessary changes to the working paper for both this proposal and the previously "explicit" keyword as added in Valley Forge. The intent of this proposal is to allow the "explicit" keyword to be specified on operator conversion functions (in addition to constructors); and that such an operator conversion would define a conversion (in a syntacticly intuitive manner) that is not invoked implicitly, but can be invoked explicitly. The "explicit" keyword is a function specifier (like virtual); but it effects only the operator that it applies to, and has no direct effect on related operators in derived classes ("explicit" is not "inherited" like virtual). Conversion operators marked with the "explicit" specifier are "explicit user defined conversions". Explicit user defined conversions are not considered when determining if there is an implicit conversion from one type to another. An explicit user defined conversion is invoked by a static cast operation when the static cast operation names an "exact match" (sequence of zero or more trivial conversions [over.match.args]) for the type named in the explicit user defined conversion. (Note the previous sentence answers the question "What counts as an explicit use of a conversion?". I attempt to justify this choice below.) Explicit conversion operators can also be invoked by those cast notations that are defined in terms of the static cast operation (like the "cast notation cast" and the "functional notation cast"). Also, some clarifications for explicit constructors. "explicit" may be specified for any constructor, not just those that are conversions. When applied to a non-conversion-constructor, the keyword has no additional effect (in particular it does not change any of the behaviors of default or copy constructors). Page 2 What counts as an explicit use of a conversion? Does the type named in the cast operation have to be "the same" as the type named in the operator conversion function? If not, what relationship must they have? For example, are these explicit uses of a operator conversion? class X { public: explicit operator int(); ... }; X x; ... (short)x ... // This is an explicit use of cast, // is it an explicit use of the operator? // The sequence is X->int->short. // This proposal says NO; // and thus this would be an error. class Y { public: explicit operator const int() const; ... }; Y y; ... (int)y ... // sequence Y->const int->int // This proposal says YES. // and so this would not be an error class Z { public: explicit operator char* (); ... }; Z z; ... (const char*)z ... // sequence Z->char*->const char* // proposal says YES; not error. I chose "exact match" (sequence of zero or more trivial conversions) mostly by intuition, followed by some testing of the corner cases I could think of. I think "exact match" is the right choice. We may want to discuss this more on the reflector, or at Austin. I'll try for a better justification if others don't agree with my choice. Page 3 Changes to the Working Paper: To 7.1.2 [dcl.fct.spec] add "explicit" to the list of function-specifiers. add the following restriction on its use: "explicit" shall only be specified inside class name definitions on on the declarations (or definitions) of Constructors [class.conv.ctor] and Conversion Functions [class.conv.fct]. "explicit" may be specified on constructors which are not user defined conversions (those that cannot be called with a single argument), but the specifier has no effect on the use of the constructor. "explicit" declares a constructor to be an "explicit constructor", and a conversion function to be an "explicit conversion function". Jointly, explicit constructors and explicit conversion functions are called "explicit user defined conversions". To 5.2.8 [expr.static.cast] add: Any value may be explicitly converted to the type named in a static_cast, if the static_cast invokes an explicit user defined conversion. A static_cast invokes an explicit constructor if the static_cast names a qualified or unqualified version of a class type, and that class type has an explicit constructor, and that constructor can be invoked with the operand of the static_cast. A static_cast invokes an explicit conversion function if the type named in the static_cast would be an "exact match" (a sequence of zero or more trivial conversions) for the result (value and type) of a conversion function, and if the operand of the static_cast can be implicitly converted to the class type of the class containing the conversion function. [Feel free to improve on this.] To 12.3 [class.conv] Change paragraph 2 to: Such conversions are called "user-defined conversions". User-defined conversions may be implicit, or explicit (see [dcl.fct.spec]). Implicit user-defined conversions are used implicitly in addition to standard conversions (4). For example, ... but also with an argument of type T where and implicit conversion exists. Implicit user defined conversions are used similarly in ... 12.3.1 [class.conv.ctor] and 12.3.2 [class.conv.fct] may need changing to clarify that the comments therein apply only to implicit conversions. Page 4 Also the WP should be searched for instances of "user-defined conversion" that need to be changed to "implicit user-defined conversion".