General topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
General | |||||||||||||||||||||
Literals | |||||||||||||||||||||
Operators | |||||||||||||||||||||
Conversions | |||||||||||||||||||||
|
Enablesimplicit conversion orexplicit conversion from aclass type to another type.
Contents |
Conversion function is declared like anon-static member function or memberfunction template with no parameters, no explicit return type, and with the name of the form:
operator conversion-type-id | (1) | ||||||||
explicit operator conversion-type-id | (2) | (since C++11) | |||||||
explicit ( expression) operator conversion-type-id | (3) | (since C++20) | |||||||
conversion-type-id is atype-id except that function and array operators[]
or()
are not allowed in its declarator (thus conversion to types such as pointer to array requires a type alias/typedef or an identity template: see below). Regardless of typedef,conversion-type-id cannot represent an array or a function type.
Although the return type is not allowed in the declaration of a user-defined conversion function, thedecl-specifier-seq ofthe declaration grammar may be present and may include any specifier other thantype-specifier or the keywordstatic
, In particular, besidesexplicit
, the specifiersinline
,virtual
,constexpr
(since C++11),consteval
(since C++20), andfriend
are also allowed (note thatfriend
requires a qualified name:friend A::operator B();).
When such member function is declared in class X, it performs conversion from X toconversion-type-id:
struct X{// implicit conversion operatorint()const{return7;} // explicit conversionexplicit operatorint*()const{return nullptr;} // Error: array operator not allowed in conversion-type-id// operator int(*)[3]() const { return nullptr; } using arr_t=int[3]; operator arr_t*()const{return nullptr;}// OK if done through typedef// operator arr_t () const; // Error: conversion to array not allowed in any case}; int main(){ X x; int n=static_cast<int>(x);// OK: sets n to 7int m= x;// OK: sets m to 7 int* p=static_cast<int*>(x);// OK: sets p to null// int* q = x; // Error: no implicit conversion int(*pa)[3]= x;// OK}
User-defined conversion function is invoked in the second stage of theimplicit conversion, which consists of zero or oneconverting constructor or zero or one user-defined conversion function.
If both conversion functions and converting constructors can be used to perform some user-defined conversion, the conversion functions and constructors are both considered byoverload resolution incopy-initialization andreference-initialization contexts, but only the constructors are considered indirect-initialization contexts.
struct To{ To()=default; To(conststruct From&){}// converting constructor}; struct From{ operator To()const{return To();}// conversion function}; int main(){ From f; To t1(f);// direct-initialization: calls the constructor// Note: if converting constructor is not available, implicit copy constructor// will be selected, and conversion function will be called to prepare its argument // To t2 = f; // copy-initialization: ambiguous// Note: if conversion function is from a non-const type, e.g.// From::operator To();, it will be selected instead of the ctor in this case To t3=static_cast<To>(f);// direct-initialization: calls the constructorconst To& r= f;// reference-initialization: ambiguous}
Conversion function to its own (possibly cv-qualified) class (or to a reference to it), to the base of its own class (or to a reference to it), and to the typevoid can be defined, but can not be executed as part of the conversion sequence, except, in some cases, throughvirtual dispatch:
struct D; struct B{virtual operator D()=0;}; struct D: B{ operator D() override{return D();}}; int main(){ D obj; D obj2= obj;// does not call D::operator D() B& br= obj; D obj3= br;// calls D::operator D() through virtual dispatch}
It can also be called using member function call syntax:
struct B{}; struct X: B{ operator B&(){return*this;};}; int main(){ X x; B& b1= x;// does not call X::operatorB&() B& b2=static_cast<B&>(x);// does not call X::operatorB& B& b3= x.operator B&();// calls X::operatorB&}
When making an explicit call to the conversion function,conversion-type-id is greedy: it is the longest sequence of tokens that could possibly form aconversion-type-id(including attributes, if any)(since C++11):
& x.operatorint* a;// error: parsed as & (x.operator int*) a,// not as & (x.operator int) * a operatorint[[noreturn]]();// error: noreturn attribute applied to a type
The placeholderauto can be used inconversion-type-id, indicating adeduced return type: struct X{ operatorint();// OK operatorauto()->short;// error: trailing return type not part of syntax operatorauto()const{return10;}// OK: deduced return type operator decltype(auto)()const{return10l;}// OK: deduced return type}; Note: aconversion function template is not allowed to have a deduced return type. | (since C++14) |
Conversion functions can be inherited and can bevirtual, but cannot bestatic. A conversion function in the derived class does not hide a conversion function in the base class unless they are converting to the same type.
Conversion function can be a template member function, for example,std::auto_ptr<T>::operator auto_ptr<Y>
. Seemember template andtemplate argument deduction for applicable special rules.
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 296 | C++98 | conversion functions could be static | they cannot be declared static |
CWG 2016 | C++98 | conversion functions could not specify return types, but the types are present inconversion-type-id | return types cannot be specified in the declaration specifiers of conversion functions |
CWG 2175 | C++11 | it was unclear whether the[[noreturn]] in operatorint[[noreturn]](); is parsed as a part of noptr-declarator (of function declarator) orconversion-type-id | it is parsed as a part of conversion-type-id |