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 | |||||||||||||||||||||
|
Implicit conversions are performed whenever an expression of some typeT1
is used in context that does not accept that type, but accepts some other typeT2
; in particular:
T2
as parameter;T2
;T2
, includingreturn
statement in a function returningT2
;T2
is integral type);T2
isbool).The program is well-formed (compiles) only if there exists one unambiguousimplicit conversion sequence fromT1
toT2
.
If there are multiple overloads of the function or operator being called, after the implicit conversion sequence is built fromT1
to each availableT2
,overload resolution rules decide which overload is compiled.
Note: in arithmetic expressions, the destination type for the implicit conversions on the operands to binary operators is determined by a separate set of rules:usual arithmetic conversions.
Contents |
Implicit conversion sequence consists of the following, in this order:
When considering the argument to a constructor or to a user-defined conversion function, only one standard conversion sequence is allowed (otherwise user-defined conversions could be effectively chained). When converting from one non-class type to another non-class type, only a standard conversion sequence is allowed.
A standard conversion sequence consists of the following, in this order:
3) zero or onefunction pointer conversion; | (since C++17) |
A user-defined conversion consists of zero or one non-explicit single-argumentconverting constructor or non-explicitconversion function call.
An expressione is said to beimplicitly convertible toT2
if and only ifT2
can becopy-initialized frome, that is the declarationT2 t= e; is well-formed (can be compiled), for some invented temporaryt
. Note that this is different fromdirect initialization (T2 t(e)), where explicit constructors and conversion functions would additionally be considered.
In the following contexts, the typebool is expected and the implicit conversion is performed if the declarationbool t(e); is well-formed (that is, an explicit conversion function such asexplicit T::operatorbool()const; is considered). Such expressione is said to becontextually converted tobool.
| (since C++11) |
In the following contexts, a context-specific typeT
is expected, and the expressione of class typeE
is only allowed if
| (until C++14) |
| (since C++14) |
Such expressione is said to becontextually implicitly converted to the specified typeT
.Note that explicit conversion functions are not considered, even though they are considered in contextual conversions tobool.(since C++11)
T
is any object pointer type);T
is any integral or unscoped enumeration type, the selected user-defined conversion function must beconstexpr);switch
statement (T
is any integral or enumeration type).#include <cassert> template<typename T>class zero_init{ T val;public: zero_init(): val(static_cast<T>(0)){} zero_init(T val): val(val){} operator T&(){return val;} operator T()const{return val;}}; int main(){ zero_init<int> i;assert(i==0); i=7;assert(i==7); switch(i){}// error until C++14 (more than one conversion function)// OK since C++14 (both functions convert to the same type int)switch(i+0){}// always okay (implicit conversion)}
Value transformations are conversions that change thevalue category of an expression. They take place whenever an expression appears as an operand of an operator that expects an expression of a different value category:
| (since C++17) |
Anlvalue(until C++11)Aglvalue(since C++11) of any non-function, non-array typeT
can be implicitly converted toanrvalue(until C++11)aprvalue(since C++11):
T
is not a class type, the type of thervalue(until C++11)prvalue(since C++11) is the cv-unqualified version ofT
.T
.If an lvalue-to-rvalue conversion from anincomplete type is required by a program, that program is ill-formed.
Given the object to which thelvalue(until C++11)glvalue(since C++11) refers asobj:
| (until C++11) | ||||
| (since C++11) |
This conversion models the act of reading a value from a memory location into a CPU register.
Anlvalue orrvalue of type “array ofNT
” or “array of unknown bound ofT
” can be implicitly converted to aprvalue of type “pointer toT
”.If the array is a prvalue,temporary materialization occurs.(since C++17) The resulting pointer refers to the first element of the array (seeArray-to-pointer decay for details).
Anlvalue of function type can be implicitly converted to aprvaluepointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.
Temporary materializationAprvalue of any complete type If struct S{int m;};int i= S().m;// member access expects glvalue as of C++17;// S() prvalue is converted to xvalue Temporary materialization occurs in the following situations:
Note that temporary materialization doesnot occur when initializing an object from a prvalue of the same type (bydirect-initialization orcopy-initialization): such object is initialized directly from the initializer. This ensures “guaranteed copy elision”. | (since C++17) |
prvalues of small integral types (such aschar) and unscoped enumeration types may be converted to prvalues of larger integral types (such asint). In particular,arithmetic operators do not accept types smaller thanint as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion, if applicable. This conversion always preserves the value.
The following implicit conversions in this section are classified asintegral promotions.
Note that for a given source type, the destination type of integral promotion is unique, And all other conversions are not promotions. For example,overload resolution chooseschar ->int (promotion) overchar ->short (conversion).
A prvalue of typebool can be converted to a prvalue of typeint, withfalse becoming0 andtrue becoming1.
For a prvalueval of an integral typeT
exceptbool:
T
ischar8_t,(since C++20)char16_t,char32_t or(since C++11)wchar_t,val can be converted according to the rules specified in item (3);T
is lower than the rank ofint:T
;T
is one of the given character types),val can be converted to a prvalue of the first of the following types that can represent all the values of its underlying type:
| (since C++11) |
A prvalue of an unscopedenumeration type whose underlying type is not fixed can be converted to a prvalue of the first type from the following list able to hold their entire value range:
| (since C++11) |
A prvalue of an unscoped enumeration type whose underlying type is fixed can be converted to its underlying type. Moreover, if the underlying type is also subject to integral promotion, to the promoted underlying type. Conversion to the unpromoted underlying type is better for the purposes ofoverload resolution. | (since C++11) |
Aprvalue of typefloat can be converted to a prvalue of typedouble. The value does not change.
This conversion is calledfloating-point promotion.
Unlike the promotions, numeric conversions may change the values, with potential loss of precision.
Aprvalue of an integer type or of an unscoped enumeration type can be converted to any other integer type. If the conversion is listed under integral promotions, it is a promotion and not a conversion.
Aprvalue of a floating-point type can be converted to a prvalue of any other floating-point type. | (until C++23) |
Aprvalue of a floating-point type can be converted to a prvalue of any other floating-point type with a greater or equalfloating-point conversion rank. Aprvalue of a standard floating-point type can be converted to a prvalue of any other standard floating-point type.
| (since C++23) |
If the conversion is listed under floating-point promotions, it is a promotion and not a conversion.
Aprvalue of floating-point type can be converted to a prvalue of any integer type. The fractional part is truncated, that is, the fractional part is discarded.
A prvalue of integer or unscoped enumeration type can be converted to a prvalue of any floating-point type. The result is exact if possible.
Anull pointer constant can be converted to any pointer type, and the result is the null pointer value of that type. Such conversion (known asnull pointer conversion) is allowed to convert to a cv-qualified type as a single conversion, that is, it is not considered a combination of numeric and qualifying conversions.
Aprvalue pointer to any (optionally cv-qualified) object typeT
can be converted to a prvalue pointer to (identically cv-qualified)void. The resulting pointer represents the same location in memory as the original pointer value.
A prvalueptr of type “pointer to (possibly cv-qualified)Derived
” can be converted to a prvalue of type “pointer to (possibly cv-qualified)Base
”, whereBase
is abase class ofDerived
, andDerived
is acomplete class type. If theBase
is inaccessible or ambiguous, the program is ill-formed.
Base
is avirtual base class ofDerived
andptr does not point to an object whose type issimilar toDerived
and that is within itslifetime or within its period of construction or destruction, the behavior is undefined.Anull pointer constant can be converted to any pointer-to-member type, and the result is the null member pointer value of that type. Such conversion (known asnull member pointer conversion) is allowed to convert to a cv-qualified type as a single conversion, that is, it is not considered a combination of numeric and qualifying conversions.
Aprvalue of type “pointer to member ofBase
of type (possibly cv-qualified)T
” can be converted to a prvalue of type “pointer to member ofDerived
of type (identically cv-qualified)T
”, whereBase
is a base class ofDerived
, andDerived
is a complete class type. IfBase
is inaccessible, ambiguous, or virtual base ofDerived
or is a base of some intermediate virtual base ofDerived
, the program is ill-formed.
Derived
does not contain the original member and is not a base class of the class containing the original member, the behavior is undefined.Derived
object, and it will access the member within theBase
base subobject of thatDerived
object.Aprvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of typebool.
The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values becomefalse. All other values becometrue.
In the context of adirect-initialization, abool object may be initialized from a prvalue of typestd::nullptr_t, includingnullptr. The resulting value isfalse. However, this is not considered to be an implicit conversion. | (since C++11) |
Generally speaking:
T
can be converted to a prvalue pointer to a more cv-qualified same typeT
(in other words, constness and volatility can be added).T
in classX
can be converted to a prvalue pointer to member ofmore cv-qualified typeT
in classX
.The formal definition of “qualification conversion” is givenbelow.
Informally, two types aresimilar if, ignoring top-level cv-qualification:
For example:
Formally, type similarity is defined in terms of qualification-decomposition.
Aqualification-decomposition of a typeT
is a sequence of componentscv_i
andP_i
such thatT
is “cv_0 P_0 cv_1 P_1 ... cv_n−1 P_n−1 cv_n U
” for non-negativen, where
cv_i
is a set ofconst andvolatile, andP_i
isC_i
of type”,IfP_i
designates an array, the cv-qualifierscv_i+1
on the element type are also taken as the cv-qualifierscv_i
of the array.
// T is “pointer to pointer to const int”, it has 3 qualification-decompositions:// n = 0 -> cv_0 is empty, U is “pointer to pointer to const int”// n = 1 -> cv_0 is empty, P_0 is “pointer to”,// cv_1 is empty, U is “pointer to const int”// n = 2 -> cv_0 is empty, P_0 is “pointer to”,// cv_1 is empty, P_1 is “pointer to”,// cv_2 is “const", U is “int”using T=constint**; // substitute any of the following type to U gives one of the decompositions:// U = U0 -> the decomposition with n = 0: U0// U = U1 -> the decomposition with n = 1: pointer to [U1]// U = U2 -> the decomposition with n = 2: pointer to [pointer to [const U2]]using U2=int;using U1=const U2*;using U0= U1*;
Two typesT1
andT2
aresimilar if there exists a qualification-decomposition for each of them, where all following conditions are satisfied for the two qualification-decompositions:
U
are the same.P_i
components are the sameor one is “array ofN_i” and the other is “array of unknown bound of”(since C++20) for alli.// the qualification-decomposition with n = 2:// pointer to [volatile pointer to [const int]]using T1=constint*volatile*; // the qualification-decomposition with n = 2:// const pointer to [pointer to [int]]using T2=int**const; // For the two qualification-decompositions above// although cv_0, cv_1 and cv_2 are all different,// they have the same n, U, P_0 and P_1,// therefore types T1 and T2 are similar.
In the description below, the longest qualification-decomposition of typeTn
is denoted asDn
, and its components are denoted ascvn_i
andPn_i
.
A prvalue expression of type
Thequalification-combined type of two types
| (until C++20) |
Thequalification-combined type of two types
A prvalue of type | (since C++20) |
// longest qualification-decomposition of T1 (n = 2):// pointer to [pointer to [char]]using T1=char**; // longest qualification-decomposition of T2 (n = 2):// pointer to [pointer to [const char]]using T2=constchar**; // Determining the cv3_i and T_i components of D3 (n = 2):// cv3_1 = empty (union of empty cv1_1 and empty cv2_1)// cv3_2 = “const” (union of empty cv1_2 and “const” cv2_2)// P3_0 = “pointer to” (no array of unknown bound, use P1_0)// P3_1 = “pointer to” (no array of unknown bound, use P1_1)// All components except cv_2 are the same, cv3_2 is different from cv1_2,// therefore add “const” to cv3_k for each k in [1, 2): cv3_1 becomes “const”.// T3 is “pointer to const pointer to const char”, i.e., const char* const *.using T3=/* the qualification-combined type of T1 and T2 */; int main(){constchar c='c';char* pc; T1 ppc=&pc; T2 pcc= ppc;// Error: T3 is not the same as cv-unqualified T2,// no implicit conversion. *pcc=&c;*pc='C';// If the erroneous assignment above is allowed,// the const object “c” may be modified.}
Note that in the C programming language,const/volatile can be added to the first level only:
char** p=0;char*const* p1= p;// OK in C and C++constchar*const* p2= p;// error in C, OK in C++
Function pointer conversions
void(*p)();void(**pp)()noexcept=&p;// error: cannot convert to pointer to noexcept function struct S{typedefvoid(*p)(); operator p();};void(*q)()noexcept= S();// error: cannot convert to pointer to noexcept function | (since C++17) |
Until C++11, designing a class that should be usable in boolean contexts (e.g.if(obj){ ...}) presented a problem: given a user-defined conversion function, such asT::operatorbool()const;, the implicit conversion sequence allowed one additional standard conversion sequence after that function call, which means the resultantbool could be converted toint, allowing such code asobj<<1; orint i= obj;.
One early solution for this can be seen instd::basic_ios, which initially definesoperatorvoid*, so that the code such asif(std::cin){...} compiles becausevoid* is convertible tobool, butint n=std::cout; does not compile becausevoid* is not convertible toint. This still allows nonsense code such asdeletestd::cout; to compile.
Many pre-C++11 third party libraries were designed with a more elaborate solution, known as theSafe Bool idiom.std::basic_ios also allowed this idiom viaLWG issue 468, andoperatorvoid* was replaced (seenotes).
Since C++11,explicit bool conversion can also be used to resolve the safe bool problem.
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 170 | C++98 | the behavior of pointer-to-member conversions was unclear if the derived class does not have the original member | made clear |
CWG 172 | C++98 | enumeration type was promoted based on its underlying type | based on its value range instead |
CWG 330 (N4261) | C++98 | the conversion fromdouble*const(*p)[3] todoubleconst*const(*p)[3] was invalid | made valid |
CWG 519 | C++98 | null pointer values were not guaranteed to be preserved when converting to another pointer type | always preserved |
CWG 616 | C++98 | the behavior of lvalue to rvalue conversion of any uninitialized object and pointer objects of invalid values was always undefined | indeterminateunsignedchar is allowed; use of invalid pointers is implementation-defined |
CWG 685 | C++98 | the underlying type of an enumeration type was not prioritized in integral promotion if it is fixed | prioritized |
CWG 707 | C++98 | integer to floating point conversion had defined behavior in all cases | the behavior is undefined if the value being converted is out of the destination range |
CWG 1423 | C++11 | std::nullptr_t was convertible tobool in both direct- and copy-initialization | direct-initialization only |
CWG 1773 | C++11 | a name expression that appears in a potentially-evaluated expression such that the object named is not odr-used might still be evaluated during an lvalue-to-rvalue conversion | not evaluated |
CWG 1781 | C++11 | std::nullptr_t tobool was considered an implicit conversion even though it is only valid for direct-initialization | no longer considered an implicit conversion |
CWG 1787 | C++98 | the behavior of reading from an indeterminate unsignedchar cached in a register was undefined | made well-defined |
CWG 1981 | C++11 | contextual conversions considered explicit conversion functions | not considered |
CWG 2140 | C++11 | it was unclear whether lvalue-to-rvalue conversions from std::nullptr_t lvalues fetch these lvalues from memory | not fetched |
CWG 2310 | C++98 | for derived-to-base pointer conversions and base-to-derived pointer-to-member conversions, the derived class type could be incomplete | must be complete |
CWG 2484 | C++20 | char8_t andchar16_t had different integral promotion strategies, but they can fit both of them | char8_t should be promoted in the same way aschar16_t |
CWG 2485 | C++98 | integral promotions involving bit-fields were not specified well | improved the specification |
CWG 2813 | C++23 | temporary materialization would occur when an explicit object member function of a class prvalue is invoked | will not occur in this case |
CWG 2861 | C++98 | a pointer to a type-inaccessible object could be converted a pointer to a base class subobject | the behavior is undefined in this case |
CWG 2879 | C++17 | temporary materialization conversion was applied on prvalue as an operand of an operator that expects glvalue | not applied in some cases |
CWG 2899 | C++98 | lvalue-to-rvalue conversions could be applied to lvalues designating objects with invalid value representations | the behavior is undefined in this case |
CWG 2901 | C++98 | the result of lvalue-to-rvalue conversion from anunsignedint lvalue referring to anint object with value-1 was unclear | made clear |
C documentation forImplicit conversions |