A class in C++ can define one or several conversion operators. Some of them can be with auto-deduction of resulting type: operator auto
. And all compilers allow the programmer to mark any operator as deleted, and operator auto
as well. For concrete type the deletion means that an attempt to call such conversion will result in compilation error. But what could be the purpose of operator auto() = delete
?
Consider an example:
struct A {
operator auto() = delete;
};
struct B : A {
operator auto() { return 1; }
};
int main() {
B b;
A a = b; // error in Clang
int i = b; // error in Clang and GCC
int j = a; // error in Clang and GCC and MSVC
}
Since the compiler is unable to deduce the resulting type, it actually prohibits any conversion from this class or from derived classes with the error:
function 'operator auto' with deduced return type cannot be used before it is defined.
Demo: https://gcc.godbolt.org/z/zz77M5zsx
Side note that compilers slightly diverge in what conversions are still allowed (e.g. GCC and MSVC permit the conversion to base class), which one of them is right here?
But what could be the purpose of
operator auto() = delete?
What would be the purpose of the following function?
auto f() = delete;
As per the grammar functions, [dcl.fct.def.general]/1, the function-body of a function-definition may be = delete
; e.g., it is syntactically valid to define a function as deleted.
C++14 introduced auto
return type deduction for functions, and given the allowed grammar for function definitions, as per C++14 the grammar allows explicitly-deleting a function with auto
return type.
Whether this corner case is useful or not is not really for the language ponder about, as there is always a cost of introducing corner cases (e.g. "the grammar for definitions of functions shall have a special case for auto
type deduction"). Whilst there are limitations on where one may provide explicitly-defaulted function definitions ([dcl.fct.def.default]), the same restrictions do not apply for explicitly-deleted function definitions ([dcl.fct.def.delete]).
which one of them is right here?
A a = b; // error in Clang
Clang is arguable wrong to pick the user-defined conversion function for this initialization. As per [dcl.init.general]/15.6, /15.6.2:
Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. [...]
takes precedence over /15.6.3:
Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversions that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in [over.match.copy], and the best one is chosen through overload resolution ([over.match]). [...]
As a user of the language, providing a deleted definition of a function with auto
return type could be used to semantically mark that no one should provide any kind of overload of a given function name.
auto f() = delete; // never expose a valid overload for f()
// elsewhere:
int f() { return 42; }
// error: functions that differ only in
// their return type cannot be overloaded
For the special case of user-defined conversion operators, an explicitly-default auto
return type user-defined conversion function can be used e.g. in a intended-for-composition base class, similar to Scott Meyers C++03 trick of making a class non-copyable (before C++11 introduced = delete
).
struct NoUserDefinedConversionFunctionsAllowed {
operator auto() = delete;
};
struct S : NoUserDefinedConversionFunctionsAllowed {
operator int() { return 1; } // can never be used
};