Namespaces
Variants

cpp/language/implicit conversion: Difference between revisions

From cppreference.com
explain without using "other than", "whose"
Xmcgcg (talk | contribs)
Added CWG issue #2901 DR (part 1/3).
 
(26 intermediate revisions by 10 users not shown)
Line 6: Line 6:
* when the expression is used as an operand with an operator that expects {{tt|T2}};
* when the expression is used as an operand with an operator that expects {{tt|T2}};
* when initializing a new object of type {{tt|T2}}, including {{tt|return}} statement in a function returning {{tt|T2}};
* when initializing a new object of type {{tt|T2}}, including {{tt|return}} statement in a function returning {{tt|T2}};
* when the expression is used in a {{tt|switch}} statement ({{tt|T2}} is integral type);
* when the expression is used in a {{|switch}} statement ({{tt|T2}} is integral type);
* when the expression is used in an {{tt|if}} statement or a loop ({{tt|T2}} is {{c/core|bool}}).
* when the expression is used in an {{|if}} statement or a loop ({{tt|T2}} is {{c/core|bool}}).
The program is well-formed (compiles) only if there exists one unambiguous ''implicit conversion sequence'' from {{tt|T1}} to {{tt|T2}}.  
The program is well-formed (compiles) only if there exists one unambiguous ''implicit conversion sequence'' from {{tt|T1}} to {{tt|T2}}.  


Line 20: Line 20:
@3@ zero or one ''standard conversion sequence'' (only if a user-defined conversion is used).
@3@ zero or one ''standard conversion sequence'' (only if a user-defined conversion is used).


When considering the argument to a constructor or to a user-defined conversion function, only a 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.
When considering the argument to a constructor or to a user-defined conversion function, only 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:
A standard conversion sequence consists of the following, in this order:
@1@ zero or one conversion from the following set: ''lvalue-to-rvalue conversion'', ''array-to-pointer conversion'', and ''function-to-pointer conversion'';
@1@ zero or one conversion from the following set:
''lvalue-to-rvalue conversion'',
''array-to-pointer conversion'', and
''function-to-pointer conversion'';
@2@ zero or one ''numeric promotion'' or ''numeric conversion'';
@2@ zero or one ''numeric promotion'' or ''numeric conversion'';


Line 38: Line 41:
{{rrev|since=c++11|
{{rrev|since=c++11|
In the following contexts, the type {{c/core|bool}} is expected and the implicit conversion is performed if the declaration {{c|1=bool t(e);}} is well-formed (that is, an explicit conversion function such as {{c|explicit T::operator bool() const;}} is considered). Such expression {{c|e}} is said to be ''contextually converted to {{c/core|bool}}''.
In the following contexts, the type {{c/core|bool}} is expected and the implicit conversion is performed if the declaration {{c|1=bool t(e);}} is well-formed (that is, an explicit conversion function such as {{c|explicit T::operator bool() const;}} is considered). Such expression {{c|e}} is said to be ''contextually converted to {{c/core|bool}}''.
:* the controlling expression of {{c/core|if}}, {{c/core|while}}, {{c/core|for}};
* the controlling expression of {{c/core|if}}, {{c/core|while}}, {{c/core|for}};
:* the operands of the built-in logical operators {{tt|!}}, {{tt|&&}} and {{tt|{{!!}}}};
* the operands of the built-in logical operators {{tt|!}}, {{tt|&&}} and {{tt|{{!!}}}};
:* the first operand of the conditional operator {{tt|?:}};
* the first operand of the conditional operator {{tt|?:}};
:* the predicate in a {{rlpt|static_assert}} declaration;
* the predicate in a {{rlpt|static_assert}} declaration;
:* the expression in a {{rlpt|noexcept spec|noexcept}} specifier;
* the expression in a {{rlpt|noexcept spec|noexcept}} specifier;
{{rrev|since=c++20|
{{rrev|since=c++20|
:* the expression in an {{rlpt|explicit}} specifier;
* the expression in an {{rlpt|explicit}} specifier;
}}
}}
}}
}}
Line 58: Line 61:
Such expression {{c|e}} is said to be ''contextually implicitly converted'' to the specified type {{tt|T}}. {{rev inl|since=c++11|Note that explicit conversion functions are not considered, even though they are considered in contextual conversions to {{c/core|bool}}.}}
Such expression {{c|e}} is said to be ''contextually implicitly converted'' to the specified type {{tt|T}}. {{rev inl|since=c++11|Note that explicit conversion functions are not considered, even though they are considered in contextual conversions to {{c/core|bool}}.}}
* the argument of the {{rlp|delete|delete-expression}} ({{tt|T}} is any object pointer type);
* the argument of the {{rlp|delete|delete-expression}} ({{tt|T}} is any object pointer type);
* {{rlp|constant expression#Integral constant expression|integral constant expression}}, where a literal class is used ({{tt|T}} is any integral or unscoped enumeration type, the selected user-defined conversion function must be {{rlp|constexpr}});
* {{|constant expression#Integral constant expression}}, where a literal class is used ({{tt|T}} is any integral or unscoped enumeration type, the selected user-defined conversion function must be {{rlp|constexpr}});
* the controlling expression of the {{rlpt|switch}} statement ({{tt|T}} is any integral or enumeration type).
* the controlling expression of the {{rlpt|switch}} statement ({{tt|T}} is any integral or enumeration type).


Line 90: Line 93:


===Value transformations===
===Value transformations===
Value transformations are conversions that change the {{rlp|value 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.
Value transformations are conversions that change the {{rlp|value 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
.


====Lvalue-to-rvalue conversion====
====Lvalue-to-rvalue conversion====
{{anchor|Lvalue to rvalue conversion}}<!-- Keep the old links valid -->
{{rev inl|until=c++11|An {{|value category#lvalue}}}}{{rev inl|since=c++11|A {{|value category#glvalue}}}} of any non-function, non-array type {{tt|T}} can be implicitly converted to {{rev inl|until=c++11|an {{|value category#rvalue}}}}{{rev inl|since=c++11|a {{|value category#prvalue}}}}:
{{rev inl|until=c++11|An {{rlp|value category#lvalue|lvalue}}}}{{rev inl|since=c++11|A {{rlp|value category#glvalue|glvalue}}}} of any non-function, non-array type {{tt|T}} can be implicitly converted to {{rev inl|until=c++11|an {{rlp|value category#rvalue|rvalue}}}}{{rev inl|since=c++11|a {{rlp|value category#prvalue|prvalue}}}}:
* If {{tt|T}} is not a class type, the type of the {{rev inl|until=c++11|rvalue}}{{rev inl|since=c++11|prvalue}} is the cv-unqualified version of {{tt|T}}.
* If {{tt|T}} is not a class type, the type of the {{rev inl|until=c++11|rvalue}}{{rev inl|since=c++11|prvalue}} is the cv-unqualified version of {{tt|T}}.
* Otherwise, the type of the {{rev inl|until=c++11|rvalue}}{{rev inl|since=c++11|prvalue}} is {{tt|T}}.
* Otherwise, the type of the {{rev inl|until=c++11|rvalue}}{{rev inl|since=c++11|prvalue}} is {{tt|T}}.


If an lvalue-to-rvalue conversion from an {{rlp|type#Incomplete type|incomplete type}} is required by a program, that program is ill-formed.
If an lvalue-to-rvalue conversion from an {{|type#Incomplete type}} is required by a program, that program is ill-formed.


{{rev begin}}
{{rev begin}}
{{rev|until=c++11|
{{rev|until=c++11|
When an lvalue-to-rvalue conversion occurs within the operand of {{rlpt|sizeof}}, the value contained in the referenced object is not accessed, since that operator {{rlp|expressions#Potentially-evaluated expressions|does not evaluate}} its operand.
When an lvalue-to-rvalue conversion occurs within the operand of {{rlpt|sizeof}}, the value contained in is not accessed, since that operator {{rlp|expressions#Potentially-evaluated expressions|does not evaluate}} its operand
 
.
}}
}}
{{rev|since=c++11|
{{rev|since=c++11|
When an lvalue-to-rvalue conversion is applied to an expression {{c|E}}, the value contained in the referenced object is not accessed if:
When an lvalue-to-rvalue conversion is applied to an expression {{c|E}}, the value contained in is not accessed if:
* {{c|E}} is not {{rlp|expressions#Potentially-evaluated expressions|potentially evaluated}}, or
* {{c|E}} is not {{rlp|expressions#Potentially-evaluated expressions|potentially evaluated}}, or
* the evaluation of {{c|E}} results in the evaluation of a member {{c|Ex}} of the set of {{rlp|definition#ODR-use|potential results}} of {{c|E}}, and {{c|Ex}} names a variable {{c|x}} that is not {{rlp|definition#ODR-use|odr-used}} by {{c|Ex}}.
* the evaluation of {{c|E}} results in the evaluation of a member {{c|Ex}} of the set of {{rlp|definition#ODR-use|potential results}} of {{c|E}}, and {{c|Ex}} names a variable {{c|x}} that is not {{rlp|definition#ODR-use|odr-used}} by {{c|Ex}}.
}}
{{rev end}}
 


{{rev begin}}
{{rev begin}}
{{rev|until=c++11|
{{rev|until=c++|
The result of the conversion is the value contained in the object indicated by the lvalue.
The result of the conversion is the .
}}
}}
{{rev|since=c++11|
{{rev|since=c++17|
The result of the conversion is determined according to the following rules:
::* conversion {{rlp|copy initialization|copy-initializes}} the [[#Temporary materialization|result object]] from the glvalue.
* If {{tt|T}} is (possibly cv-qualified) {{lc|std::nullptr_t}}, the result is a {{rlp|pointer#Null pointers|null pointer constant}}. The object to which the glvalue refers is not accessed by the conversion, so there is no side effect even if {{tt|T}} is volatile-qualified, and the glvalue can refer to an inactive member of a union.
* Otherwise, if T has a class type,
{{rrev multi|until1=c++17|rev1=
:* the conversion {{rlp|copy initialization|copy-initializes}} a {{rlp|lifetime#Temporary object lifetime|temporary}} of type {{tt|T}} from the glvalue, and the result of the conversion is a prvalue for the temporary.
|rev2=
:* the conversion {{rlp|copy initialization|copy-initializes}} the [[#Temporary materialization|result object]] from the glvalue.
}}
}}
* Otherwise, if the object to which the glvalue refers contains an invalid pointer value, the behavior is implementation-defined.
* Otherwise, {{rev inl|since=c++20|the object indicated by the glvalue is read, and}} the result is the value contained in the object.
* Otherwise, if contains an invalid pointer value, the behavior is implementation-defined.
* Otherwise, {{rev inl|since=c++20|is read, and}} the result is the value contained in the .
}}
}}
{{rev end}}
{{rev end}}
Line 134: Line 140:
====Array-to-pointer conversion====
====Array-to-pointer conversion====
{{anchor|Array to pointer conversion}}<!-- Keep the old links valid -->
{{anchor|Array to pointer conversion}}<!-- Keep the old links valid -->
An {{rlp|value category#lvalue|lvalue}} or {{rlp|value category#rvalue|rvalue}} of type "array of {{tt|N}} {{tt|T}}" or "array of unknown bound of {{tt|T}}" can be implicitly converted to a {{rlp|value category#prvalue|prvalue}} of type "pointer to {{tt|T}}". {{rev inl|since=c++17|If the array is a prvalue, [[#Temporary materialization|temporary materialization]] occurs.}} The resulting pointer refers to the first element of the array (see {{rlp|array#Array-to-pointer decay|array to pointer decay}} for details).
An {{|value category#lvalue}} or {{|value category#rvalue}} of type of {{|N}} {{tt|T}}or of unknown bound of {{tt|T}}can be implicitly converted to a {{|value category#prvalue}} of type to {{tt|T}}. {{rev inl|since=c++17|If the array is a prvalue, #Temporary materializationoccurs.}} The resulting pointer refers to the first element of the array (see {{|array#Array-to-pointer decay
 
|
to pointer }}.


{{rrev|since=c++17|
{{rrev|since=c++17|
====Temporary materialization====
====Temporary materialization====
A {{rlp|value category#prvalue|prvalue}} of any complete type {{tt|T}} can be converted to an xvalue of the same type {{tt|T}}. This conversion initializes a {{rlp|lifetime#Temporary object lifetime|temporary object}} of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object.  
A {{|value category#prvalue}} of any complete type {{tt|T}} can be converted to an xvalue of the same type {{tt|T}}. This conversion initializes a {{rlp|lifetime#Temporary object lifetime|temporary object}} of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object.
If {{tt|T}} is a class or array of class type, it must have an accessible and non-deleted destructor.
If {{tt|T}} is a class or array of class type, it must have an accessible and non-deleted destructor.
{{source|1=
{{source|1=
Line 145: Line 156:
               // S() prvalue is converted to xvalue
               // S() prvalue is converted to xvalue
}}
}}
Temporary materialization occurs in the following situations:
Temporary materialization occurs in the following situations:
* when {{rlp|reference initialization|binding a reference}} to a prvalue;
* when {{rlp|reference initialization|binding a reference}} to a prvalue;
* when performing a {{rlp|operator member access|member access}} on a class prvalue;
* when a
{{rlp|operator member |member }} a class prvalue;
* when performing an array-to-pointer conversion (see above) or {{rlp|operator member access#Built-in subscript operator|subscripting}} on an array prvalue;
* when performing an array-to-pointer conversion (see above) or {{rlp|operator member access#Built-in subscript operator|subscripting}} on an array prvalue;
* when initializing an object of type {{lc|std::initializer_list<T>}} from a {{rlp|list initialization|braced-init-list}};
* when initializing an object of type {{|std::initializer_list<T>}} from a {{rlp|initialization|braced-list}};
* when {{rlpt|typeid}} is applied to a prvalue (this is part of an unevaluated expression);
* when {{rlpt|sizeof}} is applied to a prvalue (this is part of an unevaluated expression);
* when a prvalue appears as a {{rlp|expressions#Discarded-value expressions|discarded-value expression}}.
* when a prvalue appears as a {{rlp|expressions#Discarded-value expressions|discarded-value expression}}.


Note that temporary materialization does ''not'' occur when initializing an object from a prvalue of the same type (by {{rlp|direct initialization|direct-initialization}} or {{rlp|copy initialization|copy-initialization}}): such object is initialized directly from the initializer. This ensures "guaranteed copy elision".
Note that temporary materialization does ''not'' occur when initializing an object from a prvalue of the same type (by {{rlp|direct initialization|direct-initialization}} or {{rlp|copy initialization|copy-initialization}}): such object is initialized directly from the initializer. This ensures copy .
}}
}}


====Function-to-pointer conversion====
======
{{anchor|Function to pointer}}<!-- Keep the old links valid -->
{{|to }}{{rlp||}} {{|}} to
An {{rlp|value category#lvalue|lvalue}} of function type {{tt|T}} can be implicitly converted to a {{rlp|value category#prvalue|prvalue}} {{rlp|pointer#Pointers to functions|pointer to that function}}. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.
 
 
a {{rlp||}} {{||}} -.


===Numeric promotions===
========
====Integral promotion====
prvalue of {{c/core|}} be converted to of {{c/core|int}}, {{||}} {{c|}}.
{{rlp|value category#prvalue|prvalue}}s of small integral types (such as {{c/core|char}}) may be converted to prvalues of larger integral types (such as {{c/core|int}}). In particular, {{rlp|operator arithmetic|arithmetic operators}} do not accept types smaller than {{c/core|int}} 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 are classified as integral promotions:
integral :
:* {{c/core|char}}, {{c/core|signed char}}, {{c/core|unsigned char}}, {{c/core|short}} and {{c/core|unsigned short}} can be converted to {{c/core|int}} if their respective entire value range can be held by the type {{c/core|int}}, or {{c/core|unsigned int}} otherwise;
{{c|}},
:* {{c/core|wchar_t}}{{rev inl|since=c++20|, {{c/core|char8_t}}}}{{rev inl|since=c++11|, {{c/core|char16_t}}, and {{c/core|char32_t}}}} can be converted to the first type from the following list able to hold their entire value range:
{{c|}} {{c/core|}} {{c/core|}}
::* {{c/core|int}}
{{c|}} can be converted to {{c/core|int}} if {{c/core|int}}
::* {{c/core|unsigned int}}
, {{c|
::* {{c/core|long}}
}}
::* {{c/core|unsigned long}}
* {{|}} {{rev inl|since=c++20|{{c/core|char8_t}}}}{{rev inl|since=c++11|{{c/core|char16_t}}, {{c/core|char32_t}} }} can be converted to
the first the following :
:* {{c/core|int}}
:* {{c/core|unsigned int}}
:* {{c/core|long}}
:* {{c/core|unsigned long}}
{{rrev|since=c++11|
{{rrev|since=c++11|
::* {{c/core|long long}}
:* {{c/core|long long}}
::* {{c/core|unsigned long long}}
:* {{c/core|unsigned long long
}}
}}
}}
{{rrev|since=c++11|
{{rrev|since=c++11|
:: If none of the types in the list can represent all the values of its underlying type, {{c/core|wchar_t}}{{rev inl|since=c++20|, {{c/core|char8_t}}}}, {{c/core|char16_t}}, and {{c/core|char32_t}} can be converted to its underlying type.
{{c/core|}}
}}
{{c/core|}}
:* an unscoped {{rlp|enum|enumeration}} type whose underlying type is not fixed can be converted to the first type from the following list able to hold their entire value range:
* {{rlp||type}}
::* {{c/core|int}}
:* {{|}} {{c/core|long long}}
::* {{c/core|unsigned int}}
:*
::* {{c/core|long}}
:*
::* {{c/core|unsigned long}}
{{rrev|since=c++11|
::* {{c/core|long long}}
::* {{c/core|unsigned long long}}
}}
}}
{{rrev|since=c++11|
{{rrev|since=c++11|
:: If none of the types in the list can represent all the values of the enumeration, the unscoped enumeration type can be converted to the {{rlp|types#Extended integer types|extended integer type}} with lowest {{rlp|usual arithmetic conversions#Integer conversion rank|integer conversion rank}} greater than the rank of {{c/core|long long}} in which all the values of the enumeration can be represented. If there are two such extended types, the signed one is chosen.
of unscoped enumeration type can be converted to the type the of {{|}}.
}}
}}
:* an unscoped enumeration type whose underlying type is fixed can be converted to its underlying type, and, 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 of {{rlp|overload resolution}};
:* a {{rlp|bit field|bit-field}} type can be converted to {{c/core|int}} if it can represent entire value range of the bit-field, otherwise to {{c/core|unsigned int}} if it can represent entire value range of the bit-field, otherwise no integral promotions apply;
:* the type {{c/core|bool}} can be converted to {{c/core|int}} with the value {{c|false}} becoming {{c|0}} and {{c|true}} becoming {{c|1}}.


Note that all other conversions are not promotions; for example, {{rlp|overload resolution}} chooses {{c/core|char}} -> {{c/core|int}} (promotion) over {{c/core|char}} -> {{c/core|short}} (conversion).
-
{{|}} {{c/core|}} {{c/core|}}.


====Floating-point promotion====
-point promotion.
A {{rlp|value category#prvalue|prvalue}} of type {{c/core|float}} can be converted to a prvalue of type {{c/core|double}}. The value does not change.


===Numeric conversions===
===Numeric conversions===
Line 204: Line 228:


====Integral conversions====
====Integral conversions====
A {{rlp|value category#prvalue|prvalue}} 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.
A {{|value category#prvalue}} 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.
:* If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value [[enwiki:Modular arithmetic|modulo]] {{math|2{{su|p=n}}}} where {{math|n}} is the number of bits used to represent the destination type.
* If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value enwikiModular arithmetic|modulo{{math|2{{su|p=n}}}} where {{math|n}} is the number of bits used to represent the destination type.
:: That is, depending on whether the destination type is wider or narrower, signed integers are sign-extended<ref group="footnote">This only applies if the arithmetic is two's complement which is only required for the [[cpp/types/integer|exact-width integer types]]. Note, however, that at the moment all platforms with a C++ compiler use two's complement arithmetic</ref> or truncated and unsigned integers are zero-extended or truncated respectively.
:That is, depending on whether the destination type is wider or narrower, signed integers are sign-extended<ref>This only applies if the arithmetic is two's complement which is only required for the [[cpp/types/integer|exact-width integer types]]. Note, however, that at the moment all platforms with a C++ compiler use two's complement arithmetic</ref> or truncated and unsigned integers are zero-extended or truncated respectively.
:* If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is {{rev inl|until=c++20|implementation-defined}}{{rev inl|since=c++20|the unique value of the destination type equal to the source value modulo {{math|2{{su|p=n}}}} where {{math|n}} is the number of bits used to represent the destination type.}}. (Note that this is different from {{rlp|operator arithmetic#Overflows|signed integer arithmetic overflow}}, which is undefined).
* If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is {{rev inl|until=c++20|implementation-defined}}{{rev inl|since=c++20|the unique value of the destination type equal to the source value modulo {{math|2{{su|p=n}}}} where {{math|n}} is the number of bits used to represent the destination type}} (that this is different from {{rlp|operator arithmetic#Overflows|signed integer arithmetic overflow}}, which is undefined).
:* If the source type is {{c/core|bool}}, the value {{c|false}} is converted to zero and the value {{c|true}} is converted to the value one of the destination type (note that if the destination type is {{c/core|int}}, this is an integer promotion, not an integer conversion).
* If the source type is {{c/core|bool}}, the value {{c|false}} is converted to zero and the value {{c|true}} is converted to the value one of the destination type (note that if the destination type is {{c/core|int}}, this is an integer promotion, not an integer conversion).
:* If the destination type is {{c/core|bool}}, this is a [[#Boolean conversions|boolean conversion]] (see below).
* If the destination type is {{c/core|bool}}, this is a [[#Boolean conversions|boolean conversion]] (see below).


====Floating-point conversions====
====Floating-point conversions====
{{rev begin}}
{{rev begin}}
{{rev|until=c++23|
{{rev|until=c++23|
A {{rlp|value category#prvalue|prvalue}} of a floating-point type can be converted to a prvalue of any other floating-point type.
A {{|value category#prvalue}} of a floating-point type can be converted to a prvalue of any other floating-point type.
}}
}}
{{rev|since=c++23|
{{rev|since=c++23|
A {{rlp|value category#prvalue|prvalue}} of a floating-point type can be converted to a prvalue of any other floating-point type with a greater or equal {{rlp|usual arithmetic conversions#Floating-point conversion rank|floating-point conversion rank}}.
A {{|value category#prvalue}} of a floating-point type can be converted to a prvalue of any other floating-point type with a greater or equal {{|usual arithmetic conversions#Floating-point conversion rank}}.


A {{rlp|value category#prvalue|prvalue}} of a standard floating-point type can be converted to a prvalue of any other standard floating-point type.
A {{|value category#prvalue}} of a standard floating-point type can be converted to a prvalue of any other standard floating-point type.


{{rlpt|static_cast}} can be used to explicitly convert a prvalue of floating-point type to any other floating-point type.
{{rlpt|static_cast}} can be used to explicitly convert a prvalue of floating-point type to any other floating-point type.
Line 226: Line 251:


If the conversion is listed under floating-point promotions, it is a promotion and not a conversion.
If the conversion is listed under floating-point promotions, it is a promotion and not a conversion.
:* If the source value can be represented exactly in the destination type, it does not change.
* If the source value can be represented exactly in the destination type, it does not change.
:* If the source value is between two representable values of the destination type, the result is one of those two values (it is implementation-defined which one, although if IEEE arithmetic is supported, rounding defaults [[cpp/numeric/fenv/FE_round|to nearest]]).
* If the source value is between two representable values of the destination type, the result is one of those two values (it is implementation-defined which one, although if IEEE arithmetic is supported, rounding defaults [[cpp/numeric/fenv/FE_round|to nearest]]).
:* Otherwise, the behavior is undefined.
* Otherwise, the behavior is undefined.


====Floating–integral conversions====
====Floating–integral conversions====
:* A {{rlp|value category#prvalue|prvalue}} 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. If the value cannot fit into the destination type, the behavior is undefined (even when the destination type is unsigned, modulo arithmetic does not apply). If the destination type is {{c/core|bool}}, this is a boolean conversion (see below).
A {{|value category#prvalue}} 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. If the value can fit into the destination type but cannot be represented exactly, it is implementation defined whether the closest higher or the closest lower representable value will be selected, although if IEEE arithmetic is supported, rounding defaults [[cpp/numeric/fenv/FE_round|to nearest]]. If the value cannot fit into the destination type, the behavior is undefined. If the source type is {{c/core|bool}}, the value {{c|false}} is converted to zero, and the value {{c|true}} is converted to one.
If the value cannot fit into the destination type, the behavior is undefined (even when the destination type is unsigned, modulo arithmetic does not apply).
If the destination type is {{c/core|bool}}, this is a boolean conversion (see below).
 
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.
If the value can fit into the destination type but cannot be represented exactly, it is implementation defined whether the closest higher or the closest lower representable value will be selected, although if IEEE arithmetic is supported, rounding defaults [[cpp/numeric/fenv/FE_round|to nearest]].
If the value cannot fit into the destination type, the behavior is undefined.
If the source type is {{c/core|bool}}, the value {{c|false}} is converted to zero, and the value {{c|true}} is converted to one.


====Pointer conversions====
====Pointer conversions====
:* A ''null pointer constant'' (see {{lc|NULL}}), can be converted to any pointer type, and the result is the null pointer value of that type. Such conversion (known as ''null pointer conversion'') is allowed to convert to a cv-qualified type as a single conversion, that is, it's not considered a combination of numeric and qualifying conversions.
A null pointer constant}} can be converted to any pointer type, and the result is the null pointer value of that type. Such conversion (known as ''null pointer conversion'') is allowed to convert to a cv-qualified type as a single conversion, that is, it not considered a combination of numeric and qualifying conversions.
:* A {{rlp|value category#prvalue|prvalue}} pointer to any (optionally cv-qualified) object type {{tt|T}} can be converted to a prvalue pointer to (identically cv-qualified) {{c/core|void}}. The resulting pointer represents the same location in memory as the original pointer value. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.
 
:* A prvalue pointer to a (optionally cv-qualified) derived complete class type can be converted to a prvalue pointer to its (identically cv-qualified) base class. If the base class is inaccessible or ambiguous, the conversion is ill-formed (won't compile). The result of the conversion is a pointer to the base class subobject within the pointed-to object. The null pointer value is converted to the null pointer value of the destination type.
A {{|value category#prvalue}} pointer to any (optionally cv-qualified) object type {{tt|T}} can be converted to a prvalue pointer to (identically cv-qualified) {{c/core|void}}. The resulting pointer represents the same location in memory as the original pointer value.
If the original pointer is a null pointer value, the result is a null pointer value of the destination type.
 
A prvalue to (cv-qualified) can be converted to a prvalue to (cv-qualified) base class. If the is inaccessible or ambiguous, the is ill-formed.
result is a pointer
base classwithin the .
pointer to the of the .


====Pointer-to-member conversions====
====Pointer-to-member conversions====
:* A ''null pointer constant'' (see {{lc|NULL}}) can be converted to any pointer-to-member type, and the result is the null member pointer value of that type. Such conversion (known as ''null member pointer conversion'') is allowed to convert to a cv-qualified type as a single conversion, that is, it's not considered a combination of numeric and qualifying conversions.
A null 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 as ''null member pointer conversion'') is allowed to convert to a cv-qualified type as a single conversion, that is, it not considered a combination of numeric and qualifying conversions.
:* A {{rlp|value category#prvalue|prvalue}} pointer to member of some type {{tt|T}} in a base class {{tt|B}} can be converted to a {{rlp|value category#prvalue|prvalue}} pointer to member of the same type {{tt|T}} in its derived complete class {{tt|D}}. If {{tt|B}} is inaccessible, ambiguous, or virtual base of {{tt|D}} or is a base of some intermediate virtual base of {{tt|D}}, the conversion is ill-formed (won't compile). The resulting pointer can be dereferenced with a {{tt|D}} object, and it will access the member within the {{tt|B}} base subobject of that {{tt|D}} object. The null pointer value is converted to the null pointer value of the destination type.
 
A {{|value category#prvalue}} to member of {{tt|}} {{tt|}}can be converted to a {{|}} of type {{tt|T}}class {{tt|}} . If {{tt|}} is inaccessible, ambiguous, or virtual base of {{tt|}} or is a base of some intermediate virtual base of {{tt|}}, the is ill-formed.
resulting pointer can be dereferenced with a {{tt|}} object, and it will access the member within the {{tt|}} base subobject of that {{tt|}} object.


====Boolean conversions====
====Boolean conversions====
A {{rlp|value category#prvalue|prvalue}} of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type {{c/core|bool}}.
A {{|value category#prvalue}} of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type {{c/core|bool}}.


The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become {{c|false}}. All other values become {{c|true}}.
The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become {{c|false}}. All other values become {{c|true}}.
Line 253: Line 293:


===Qualification conversions===
===Qualification conversions===
:* A {{rlp|value category#prvalue|prvalue}} of type pointer to {{rlp|cv|cv-qualified}} type {{tt|T}} can be converted to a prvalue pointer to a more cv-qualified same type {{tt|T}} (in other words, constness and volatility can be added).
:
:* A prvalue of type pointer to member of cv-qualified type {{tt|T}} in class {{tt|X}} can be converted to a prvalue pointer to member of more cv-qualified type {{tt|T}} in class {{tt|X}}.
* A {{|value category#prvalue}} of type pointer to {{rlp|cv|cv-qualified}} type {{tt|T}} can be converted to a prvalue pointer to a more cv-qualified same type {{tt|T}} (in other words, constness and volatility can be added).
"More" cv-qualified means that
* A prvalue of type pointer to member of cv-qualified type {{tt|T}} in class {{tt|X}} can be converted to a prvalue pointer to member of more cv-qualifiedtype {{tt|T}} in class {{tt|X}}.
:* a pointer to ''unqualified'' type can be converted to a pointer to {{c/core|const}};
 
:* a pointer to ''unqualified'' type can be converted to a pointer to {{c/core|volatile}};
cv-
:* a pointer to ''unqualified'' type can be converted to a pointer to {{c/core|const volatile}};
 
:* a pointer to {{c/core|const}} type can be converted to a pointer to {{c/core|const volatile}};
:* a pointer to {{c/core|volatile}} type can be converted to a pointer to {{c/core|const volatile}}.
''''
type
to to
 
{{c/core|const }} ;
:
 
 
'''' type
a {{c/core|volatile}}
 
 
;
 
:
pointer to
 
''''
 
 
 
 
type
 
can be converted to
{{c/core|const}} {{c/core|const}} {{c/core|volatile}}
* {{c|}} {{c/core|const}}.


For multi-level pointers, the following restrictions apply: a multilevel pointer {{tt|P1}} which is {{math|cv{{su|b=0|p=1}}}}-qualified pointer to {{math|cv{{su|b=1|p=1}}}}-qualified pointer to ... {{math|cv{{su|b=n-1|p=1}}}}-qualified pointer to {{math|cv{{su|b=n|p=1}}}}-qualified {{tt|T}} is convertible to a multilevel pointer {{tt|P2}} which is {{math|cv{{su|b=0|p=2}}}}-qualified pointer to {{math|cv{{su|b=1|p=2}}}}-qualified pointer to ... {{math|cv{{su|b=n-1|p=2}}}}-qualified pointer to {{math|cv{{su|b=n|p=2}}}}-qualified {{tt|T}} only if
-{{tt|}} {{|{{|}} to {{|}}
:* the number of levels {{tt|n}} is the same for both pointers;
{{|}}
{{rrev|since=c++20|
-{{|}}{{tt|}} is {{tt|}} {{|
:* at every level that array type is involved in, at least one array type has unknown bound, or both array types have same size;
{{|}} {{|}} {{|}}{{|}} {{tt|}} {{|}} {{||
}}
}}
:* if there is a {{c/core|const}} in the {{math|cv{{su|b=k|p=1}}}} qualification at some level (other than level zero) of {{tt|P1}}, there is a {{c/core|const}} in the same level {{math|cv{{su|b=k|p=2}}}} of {{tt|P2}};
{{c
:* if there is a {{c/core|volatile}} in the {{math|cv{{su|b=k|p=1}}}} qualification at some level (other than level zero) of {{tt|P1}}, there is a {{c/core|volatile}} in the same {{math|cv{{su|b=k|p=2}}}} level of {{tt|P2}};
|}} {{|{{||}}}}
{{rrev|since=c++20|
{{tt|}} is
:* if there is an array type of unknown bound at some level (other than level zero) of {{tt|P1}}, there is an array type of unknown bound in the same level of {{tt|P2}};
{{c|}} the {{|{{|
|}} }} of {{tt|}}
* is {{|}} {{|{{|}} }} {{tt|}}, {{c/core|}} {{|{{|k}} }}
 
of {{tt|}} {{|if type of {{tt|}} is {{tt|}}
}}
}}
:* if at some level {{tt|k}} the {{tt|P2}} is ''more'' cv-qualified than {{tt|P1}}{{rev inl|since=c++20| or there is an array type of known bound in {{tt|P1}} and an array type of unknown bound in {{tt|P2}}}}, then there must be a {{c/core|const}} at every single level (other than level zero) of {{tt|P2}} up until k: {{math|cv{{su|b=1|p=2}}, cv{{su|b=2|p=2}} ... cv{{su|b=k|p=2}}}}.
{{rev }}
:* same rules apply to multi-level pointers to members and multi-level mixed pointers to objects and pointers to members;
:* same rules apply to multi-level pointers that include pointers to array of known or unknown bound at any level (arrays of cv-qualified elements are considered to be identically cv-qualified themselves);
:* level zero is addressed by the rules for non-multilevel qualification conversions.


{{source|1=
{{source|1=
char** p = 0;
const char** p1 = p; // error: level 2 more cv-qualified but level 1 is not const
char
const char* const * p2 = p; // OK: level 2 more cv-qualified and const added at level 1
= char**;
volatile char * const * p3 = p; // OK: level 2 more cv-qual and const added at level 1
 
volatile const char* const* p4 = p2; // OK: 2 more cv-qual and const was already at 1
// :
const
const char**;
 
// :
and
=
// :
const const char* const *
= /-and


double *a[2][3];
double const * const (*ap)[3] = a; // OK
double * const (*ap1)[] = a;       // OK since C++20
* ;
= ; //
*
*= ;
//
}}
}}


Note that in the C programming language, const/volatile can be added to the first level only:
Note that in the C programming language, const/volatilecan be added to the first level only:
{{source|1=
{{source|1=
char** p = 0;
char** p = 0;
Line 297: Line 431:


{{rrev|since=c++17|
{{rrev|since=c++17|
====Function pointer conversions====
===Function pointer conversions===
:* A {{rlp|value category#prvalue|prvalue}} of type pointer to non-throwing function can be converted to a prvalue pointer to potentially-throwing function.
* A {{|value category#prvalue}} of type pointer to non-throwing function can be converted to a prvalue pointer to potentially-throwing function.
:* A prvalue of type pointer to non-throwing member function can be converted to a prvalue pointer to potentially-throwing member function.
* A prvalue of type pointer to non-throwing member function can be converted to a prvalue pointer to potentially-throwing member function.


{{source|1=
{{source|1=
Line 315: Line 449:


===The safe bool problem===
===The safe bool problem===
Until the introduction of explicit conversion functions in C++11, designing a class that should be usable in boolean contexts (e.g. {{c|if(obj) { ... }<!---->}}) presented a problem: given a user-defined conversion function, such as {{c|T::operator bool() const;}}, the implicit conversion sequence allowed one additional standard conversion sequence after that function call, which means the resultant {{c/core|bool}} could be converted to {{c/core|int}}, allowing such code as {{c|obj << 1;}} or {{c|1=int i = obj;}}.
Until C++11, designing a class that should be usable in boolean contexts (e.g. {{c|if (obj) { ... }<!---->}}) presented a problem: given a user-defined conversion function, such as {{c|T::operator bool() const;}}, the implicit conversion sequence allowed one additional standard conversion sequence after that function call, which means the resultant {{c/core|bool}} could be converted to {{c/core|int}}, allowing such code as {{c|obj << 1;}} or {{c|1=int i = obj;}}.
 
One early solution for this can be seen in {{lc|std::basic_ios}}, which initially defines {{c/core|operator void*}}, so that the code such as {{c|if (std::cin) {...}<!---->}} compiles because {{c/core|void*}} is convertible to {{c/core|bool}}, but {{c|1=int n = std::cout;}} does not compile because {{c/core|void*}} is not convertible to {{c/core|int}}. This still allows nonsense code such as {{c|delete std::cout;}} to compile.


Many pre-C++11 third party libraries were designed with a more elaborate solution, known as the [https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool Safe Bool idiom]. {{lc|std::basic_ios}} also allowed this idiom via {{lwg|468}}, and {{c/core|operator void*}} was replaced (see [[cpp/io/basic_ios/operator bool#Notes|here]]).
solution {{lc|std::basic_ios}}{{|}}, {{c/core|void*}} ///|.


{{rrev|since=c++11|
++11 |{{||}} {{|operator bool).
The {{rlp|explicit|explicit bool conversion}} can also be used to resolve the safe bool problem:
{{source|1=
explicit operator bool() const { ... }
}}
}}


===Footnotes===
<references group="footnote"/>


===Defect reports===
===Defect reports===
{{dr list begin}}
{{dr list begin}}
{{dr list item|wg=cwg|dr=172|std=C++98|before=enumeration type is promoted based on its underlying type|after=based on its value range instead}}
{{dr list item|wg=cwg|dr=330|std=C++98|before=conversion from {{c/core|double * const (*p)[3]}}<br>to {{c/core|double const * const (*p)[3]}} invalid|after=conversion valid}}
{{dr list item|wg=cwg|dr=172|std=C++98|before=enumeration type promoted based on its underlying type|after=based on its value range instead}}
{{dr list item|wg=cwg|dr=330|std=C++98|before=conversion from {{c/core|double* const (*p)[3]}}<br>to {{c/core|double const * const (*p)[3]}} invalid|after=valid}}
{{dr list item|wg=cwg|dr=519|std=C++98|before=null pointer values were not guaranteed to be<br>preserved when converting to another pointer type|after=always preserved}}
{{dr list item|wg=cwg|dr=519|std=C++98|before=null pointer values were not guaranteed to be<br>preserved when converting to another pointer type|after=always preserved}}
{{dr list item|wg=cwg|dr=616|std=C++98|before=the behavior of lvalue to rvalue conversion of<br>any uninitialized object and pointer objects<br>of invalid values was always undefined|after=indeterminate {{c/core|unsigned char}}<br>is allowed; use of invalid pointers<br>is implementation-defined}}
{{dr list item|wg=cwg|dr=616|std=C++98|before=the behavior of lvalue to rvalue conversion of<br>any uninitialized object and pointer objects<br>of invalid values was always undefined|after=indeterminate {{c/core|unsigned char}}<br>is allowed; use of invalid pointers<br>is implementation-defined}}
{{dr list item|wg=cwg|dr=685|std=C++98|before=the underlying type of an enumeration type was<br>not prioritized in integral promotion if it is fixed|after=prioritized}}
{{dr list item|wg=cwg|dr=685|std=C++98|before=the underlying type of an enumeration type was<br>not prioritized in integral promotion if it is fixed|after=prioritized}}
{{dr list item|wg=cwg|dr=707|std=C++98|before=integer to floating point conversion<br>had defined behavior in all cases|after=the behavior is undefined if<br>the value being converted is<br>out of the destination range}}
{{dr list item|wg=cwg|dr=707|std=C++98|before=integer to floating point conversion<br>had defined behavior in all cases|after=the behavior is undefined if<br>the value being converted is<br>out of the destination range}}
{{dr list item|wg=cwg|dr=1423|std=C++11|before={{lc|std::nullptr_t}} is convertible to {{c/core|bool}}<br>in both direct- and copy-initialization|after=direct-initialization only}}
{{dr list item|wg=cwg|dr=1423|std=C++11|before={{lc|std::nullptr_t}} convertible to {{c/core|bool}}<br>in both direct- and copy-initialization|after=direct-initialization only}}
{{dr list item|wg=cwg|dr=1773|std=C++11|before=a name expression that appears in a potentially-evaluated<br>expression such that the object named is not odr-used might<br>still be evaluated during an lvalue-to-rvalue conversion|after=not evaluated}}
{{dr list item|wg=cwg|dr=1773|std=C++11|before=a name expression that appears in a potentially-evaluated<br>expression such that the object named is not odr-used might<br>still be evaluated during an lvalue-to-rvalue conversion|after=not evaluated}}
{{dr list item|wg=cwg|dr=1781|std=C++11|before={{lc|std::nullptr_t}} to {{c/core|bool}} is considered an implicit<br>conversion even though it is only valid for direct-initialization|after=no longer considered<br>an implicit conversion}}
{{dr list item|wg=cwg|dr=1781|std=C++11|before={{lc|std::nullptr_t}} to {{c/core|bool}} considered an implicit<br>conversion even though it is only valid for direct-initialization|after=no longer considered<br>an implicit conversion}}
{{dr list item|wg=cwg|dr=1787|std=C++98|before=the behavior of reading from an indeterminate<br>{{c/core|unsigned char}} cached in a register was undefined|after=made well-defined}}
{{dr list item|wg=cwg|dr=1787|std=C++98|before=the behavior of reading from an indeterminate<br>{{c/core|unsigned char}} cached in a register was undefined|after=made well-defined}}
{{dr list item|wg=cwg|dr=1981|std=C++11|before=contextual conversions considered explicit conversion functions|after=not considered}}
{{dr list item|wg=cwg|dr=1981|std=C++11|before=contextual conversions considered explicit conversion functions|after=not considered}}
{{dr list item|wg=cwg|dr=2140|std=C++11|before=it was unclear whether lvalue-to-rvalue conversions from<br>{{lc|std::nullptr_t}} lvalues fetch these lvalues from memory|after=not fetched}}
{{dr list item|wg=cwg|dr=2140|std=C++11|before=it was unclear whether lvalue-to-rvalue conversions from<br>{{lc|std::nullptr_t}} lvalues fetch these lvalues from memory|after=not fetched}}
{{dr list item|wg=cwg|dr=2310|std=C++98|before=for derived-to-base pointer conversions and<br>base-to-derived pointer-to-member conversions,<br>the derived class type could be incomplete|after=must be complete}}
{{dr list item|wg=cwg|dr=2310|std=C++98|before=for derived-to-base pointer conversions and<br>base-to-derived pointer-to-member conversions,<br>the derived class type could be incomplete|after=must be complete}}
{{dr list item|wg=cwg|dr=2484|std=C++20|before={{c/core|char8_t}} and {{c/core|char16_t}} have different integral<br>promotion strategies, but they can fit both of them|after={{c/core|char8_t}} should be promoted<br>in the same way as {{c/core|char16_t}}}}
{{dr list item|wg=cwg|dr=2484|std=C++20|before={{c/core|char8_t}} and {{c/core|char16_t}} different integral<br>promotion strategies, but they can fit both of them|after={{c/core|char8_t}} should be promoted<br>in the same way as {{c/core|char16_t}}
}}
{{dr list end}}
{{dr list end}}



Latest revision as of 07:08, 20 January 2025

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
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
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Implicit conversions are performed whenever an expression of some type T1 is used in context that does not accept that type, but accepts some other type T2; in particular:

  • when the expression is used as the argument when calling a function that is declared with T2 as parameter;
  • when the expression is used as an operand with an operator that expects T2;
  • when initializing a new object of type T2, including return statement in a function returning T2;
  • when the expression is used in a switch statement (T2 is integral type);
  • when the expression is used in an if statement or a loop (T2 is bool).

The program is well-formed (compiles) only if there exists one unambiguous implicit conversion sequence from T1 to T2.

If there are multiple overloads of the function or operator being called, after the implicit conversion sequence is built from T1 to each available T2, 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.

Order of the conversions

Implicit conversion sequence consists of the following, in this order:

1) zero or one standard conversion sequence;
2) zero or one user-defined conversion;
3) zero or one standard conversion sequence (only if a user-defined conversion is used).

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:

1) zero or one conversion from the following set:
  • lvalue-to-rvalue conversion,
  • array-to-pointer conversion, and
  • function-to-pointer conversion;
2) zero or one numeric promotion or numeric conversion;
3) zero or one function pointer conversion;
(since C++17)
4) zero or one qualification conversion.

A user-defined conversion consists of zero or one non-explicit single-argument converting constructor or non-explicit conversion function call.

An expression e is said to be implicitly convertible to T2 if and only if T2 can be copy-initialized from e, that is the declaration T2 t = e; is well-formed (can be compiled), for some invented temporary t. Note that this is different from direct initialization (T2 t(e)), where explicit constructors and conversion functions would additionally be considered.

Contextual conversions

In the following contexts, the type bool is expected and the implicit conversion is performed if the declaration bool t(e); is well-formed (that is, an explicit conversion function such as explicit T::operator bool() const; is considered). Such expression e is said to be contextually converted to bool.

  • the controlling expression of if, while, for;
  • the operands of the built-in logical operators !, && and ||;
  • the first operand of the conditional operator ?:;
  • the predicate in a static_assert declaration;
  • the expression in a noexcept specifier;
  • the expression in an explicit specifier;
(since C++20)
(since C++11)

In the following contexts, a context-specific type T is expected, and the expression e of class type E is only allowed if

(until C++14)
  • there is exactly one type T among the allowable types such that E has non-explicit conversion functions whose return types are (possibly cv-qualified) T or reference to (possibly cv-qualified) T, and
  • e is implicitly convertible to T.
(since C++14)

Such expression e is said to be contextually implicitly converted to the specified type T. Note that explicit conversion functions are not considered, even though they are considered in contextual conversions to bool.(since C++11)

  • the argument of the delete-expression (T is any object pointer type);
  • integral constant expression, where a literal class is used (T is any integral or unscoped enumeration type, the selected user-defined conversion function must be constexpr);
  • the controlling expression of the 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

Value transformations are conversions that change the value 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:

  • Whenever a glvalue appears as an operand of an operator that requires a prvalue for that operand, the lvalue-to-rvalue, array-to-pointer, or function-to-pointer standard conversions are applied to convert the expression to a prvalue.
  • Unless otherwise specified, whenever a prvalue appears as an operand of an operator that expects a glvalue for that operand, the temporary materialization conversion is applied to convert the expression to an xvalue.
(since C++17)

Lvalue-to-rvalue conversion

An lvalue(until C++11)A glvalue(since C++11) of any non-function, non-array type T can be implicitly converted to an rvalue(until C++11)a prvalue(since C++11):

  • If T is not a class type, the type of the rvalue(until C++11)prvalue(since C++11) is the cv-unqualified version of T.
  • Otherwise, the type of the rvalue(until C++11)prvalue(since C++11) is T.

If an lvalue-to-rvalue conversion from an incomplete type is required by a program, that program is ill-formed.

Given the object to which the lvalue(until C++11)glvalue(since C++11) refers as obj:

  • When an lvalue-to-rvalue conversion occurs within the operand of sizeof, the value contained in obj is not accessed, since that operator does not evaluate its operand.
  • The result of the conversion is the value contained in obj. If one of T and the type of obj is a signed integer type, and the other is the corresponding unsigned integer type, the result is the value of type T with the same value representation of obj.
(until C++11)
  • When an lvalue-to-rvalue conversion is applied to an expression E, the value contained in obj is not accessed if:
  • The result of the conversion is determined as follows:
  • If T is (possibly cv-qualified) std::nullptr_t, the result is a null pointer constant. obj is not accessed by the conversion, so there is no side effect even if T is volatile-qualified, and the glvalue can refer to an inactive member of a union.
  • Otherwise, if T is a class type:
  • The conversion copy-initializes a temporary of type T from the glvalue, and the result of the conversion is a prvalue for the temporary.
(until C++17)
(since C++17)
  • Otherwise, if obj contains an invalid pointer value, the behavior is implementation-defined.
  • Otherwise, if the bits in the value representation of obj are not valid for obj's type, the behavior is undefined.
  • Otherwise, obj is read, and(since C++20) the result is the value contained in obj. If one of T and the type of obj is a signed integer type, and the other is the corresponding unsigned integer type, the result is the value of type T with the same value representation of obj.
(since C++11)

This conversion models the act of reading a value from a memory location into a CPU register.

Array-to-pointer conversion

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be implicitly converted to a prvalue of type “pointer to T”. If the array is a prvalue, temporary materialization occurs.(since C++17) The resulting pointer refers to the first element of the array (see Array-to-pointer decay for details).

Function-to-pointer conversion

An lvalue of function type can be implicitly converted to a prvalue pointer 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 materialization

A prvalue of any complete type T can be converted to an xvalue of the same type T. This conversion initializes a temporary object of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object.

If T is a class or array of class type, it must have an accessible and non-deleted destructor.

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 does not occur when initializing an object from a prvalue of the same type (by direct-initialization or copy-initialization): such object is initialized directly from the initializer. This ensures “guaranteed copy elision”.

(since C++17)

Integral promotion

prvalues of small integral types (such as char) and unscoped enumeration types may be converted to prvalues of larger integral types (such as int). In particular, arithmetic operators do not accept types smaller than int 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 as integral 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 chooses char -> int (promotion) over char -> short (conversion).

Promotion from integral types

A prvalue of type bool can be converted to a prvalue of type int, with false becoming 0 and true becoming 1.

For a prvalue val of an integral type T except bool:

1) If val is the result of an lvalue-to-rvalue conversion applied to a bit-field,
  • val can be converted to a prvalue of type int if int can represent all the values of the bit-field;
  • otherwise, val can be converted to unsigned int if unsigned int can represent all the values of the bit-field;
  • otherwise, val can be converted according to the rules specified in item (3).
2) Otherwise (val is not converted from a bit-field),
  • if T is char8_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);
  • otherwise, if the integer conversion rank of T is lower than the rank of int:
  • val can be converted to a prvalue of type int if int can represent all the values of T;
  • otherwise, val can be converted to a prvalue of type unsigned int.
3) In the cases specified by item (1) (a converted bit-field not fitting unsigned int) or item (2) (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:
  • int
  • unsigned int
  • long
  • unsigned long
  • long long
  • unsigned long long
  • the underlying type of T
(since C++11)

Promotion from enumeration types

A prvalue of an unscoped enumeration 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:

  • int
  • unsigned int
  • long
  • unsigned long
  • its integer conversion rank is greater than the rank of long long,
  • its integer conversion rank is the lowest among all extended integer types, and
  • it is signed if there are two types with the lowest integer conversion rank among all extended integer types.
(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 of overload resolution.

(since C++11)

Floating-point promotion

A prvalue of type float can be converted to a prvalue of type double. The value does not change.

This conversion is called floating-point promotion.

Numeric conversions

Unlike the promotions, numeric conversions may change the values, with potential loss of precision.

Integral conversions

A prvalue 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.

  • If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2n
    where n is the number of bits used to represent the destination type.
  • That is, depending on whether the destination type is wider or narrower, signed integers are sign-extended[1] or truncated and unsigned integers are zero-extended or truncated respectively.
  • If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is implementation-defined(until C++20)the unique value of the destination type equal to the source value modulo 2n
    where n is the number of bits used to represent the destination type
    (since C++20)
    (note that this is different from signed integer arithmetic overflow, which is undefined).
  • If the source type is bool, the value false is converted to zero and the value true is converted to the value one of the destination type (note that if the destination type is int, this is an integer promotion, not an integer conversion).
  • If the destination type is bool, this is a boolean conversion (see below).
  1. This only applies if the arithmetic is two's complement which is only required for the exact-width integer types. Note, however, that at the moment all platforms with a C++ compiler use two's complement arithmetic.

Floating-point conversions

A prvalue of a floating-point type can be converted to a prvalue of any other floating-point type.

(until C++23)

A prvalue of a floating-point type can be converted to a prvalue of any other floating-point type with a greater or equal floating-point conversion rank.

A prvalue of a standard floating-point type can be converted to a prvalue of any other standard floating-point type.

static_cast can be used to explicitly convert a prvalue of floating-point type to any other floating-point type.

(since C++23)

If the conversion is listed under floating-point promotions, it is a promotion and not a conversion.

  • If the source value can be represented exactly in the destination type, it does not change.
  • If the source value is between two representable values of the destination type, the result is one of those two values (it is implementation-defined which one, although if IEEE arithmetic is supported, rounding defaults to nearest).
  • Otherwise, the behavior is undefined.

Floating–integral conversions

A prvalue 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.

  • If the truncated value cannot fit into the destination type, the behavior is undefined (even when the destination type is unsigned, modulo arithmetic does not apply).
  • If the destination type is bool, this is a boolean conversion (see below).

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.

  • If the value can fit into the destination type but cannot be represented exactly, it is implementation defined whether the closest higher or the closest lower representable value will be selected, although if IEEE arithmetic is supported, rounding defaults to nearest.
  • If the value cannot fit into the destination type, the behavior is undefined.
  • If the source type is bool, the value false is converted to zero, and the value true is converted to one.

Pointer conversions

A null pointer constant can be converted to any pointer type, and the result is the null pointer value of that type. Such conversion (known as null 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.

A prvalue pointer to any (optionally cv-qualified) object type T 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.

  • If the original pointer is a null pointer value, the result is a null pointer value of the destination type.

A prvalue ptr of type “pointer to (possibly cv-qualified) Derived” can be converted to a prvalue of type “pointer to (possibly cv-qualified) Base”, where Base is a base class of Derived, and Derived is a complete class type. If the Base is inaccessible or ambiguous, the program is ill-formed.

  • If ptr is a null pointer value, the result is also a null pointer value.
  • Otherwise, if Base is a virtual base class of Derived and ptr does not point to an object whose type is similar to Derived and that is within its lifetime or within its period of construction or destruction, the behavior is undefined.
  • Otherwise, the result is a pointer to the base class subobject of the derived class object.

Pointer-to-member conversions

A null 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 as null 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.

A prvalue of type “pointer to member of Base of type (possibly cv-qualified) T” can be converted to a prvalue of type “pointer to member of Derived of type (identically cv-qualified) T”, where Base is a base class of Derived, and Derived is a complete class type. If Base is inaccessible, ambiguous, or virtual base of Derived or is a base of some intermediate virtual base of Derived, the program is ill-formed.

  • If Derived does not contain the original member and is not a base class of the class containing the original member, the behavior is undefined.
  • Otherwise, the resulting pointer can be dereferenced with a Derived object, and it will access the member within the Base base subobject of that Derived object.

Boolean conversions

A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool.

The value zero (for integral, floating-point, and unscoped enumeration) and the null pointer and the null pointer-to-member values become false. All other values become true.

In the context of a direct-initialization, a bool object may be initialized from a prvalue of type std::nullptr_t, including nullptr. The resulting value is false. However, this is not considered to be an implicit conversion.

(since C++11)

Qualification conversions

Generally speaking:

  • A prvalue of type pointer to cv-qualified type T can be converted to a prvalue pointer to a more cv-qualified same type T (in other words, constness and volatility can be added).
  • A prvalue of type pointer to member of cv-qualified type T in class X can be converted to a prvalue pointer to member of more cv-qualified type T in class X.

The formal definition of “qualification conversion” is given below.

Similar types

Informally, two types are similar if, ignoring top-level cv-qualification:

  • they are the same type; or
  • they are both pointers, and the pointed-to types are similar; or
  • they are both pointers to member of the same class, and the types of the pointed-to members are similar; or
  • they are both arrays and the array element types are similar.

For example:

  • const int* const * and int** are similar;
  • int (*)(int*) and int (*)(const int*) are not similar;
  • const int (*)(int*) and int (*)(int*) are not similar;
  • int (*)(int* const) and int (*)(int*) are similar (they are the same type);
  • std::pair<int, int> and std::pair<const int, int> are not similar.

Formally, type similarity is defined in terms of qualification-decomposition.

A qualification-decomposition of a type T is a sequence of components cv_i and P_i such that T is “cv_0 P_0 cv_1 P_1 ... cv_n−1 P_n−1 cv_n U” for non-negative n, where

  • each cv_i is a set of const and volatile, and
  • each P_i is
  • “pointer to”,
  • “pointer to member of class C_i of type”,
  • “array of N_i”, or
  • “array of unknown bound of”.

If P_i designates an array, the cv-qualifiers cv_i+1 on the element type are also taken as the cv-qualifiers cv_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 = const int**;

// 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 types T1 and T2 are similar if there exists a qualification-decomposition for each of them, where all following conditions are satisfied for the two qualification-decompositions:

  • They have the same n.
  • The types denoted by U are the same.
  • The corresponding P_i components are the same or one is “array of N_i” and the other is “array of unknown bound of”(since C++20) for all i.
// the qualification-decomposition with n = 2:
// pointer to [volatile pointer to [const int]]
using T1 = const int* 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.

Combining cv-qualifications

In the description below, the longest qualification-decomposition of type Tn is denoted as Dn, and its components are denoted as cvn_i and Pn_i.

A prvalue expression of type T1 can be converted to type T2 if all following conditions are satisfied:

  • T1 and T2 are similar.
  • For every non-zero i, if const is in cv1_i, then const is also in cv2_i, and similarly for volatile.
  • For every non-zero i, if cv1_i and cv2_i are different, then const is in cv2_k for every k in [1i).

The qualification-combined type of two types T1 and T2 is a type T3 similar to T1 such that

  • cv3_0 is empty,
  • for every non-zero i, cv3_i is the union of cv1_i and cv2_i, and
  • if cv3_i is different from cv1_i or c2_i, then const is added to cv3_k for every k in [1i).
(until C++20)

The qualification-combined type of two types T1 and T2 is a type T3 similar to T1, where D3 satisfies all following conditions:

  • cv3_0 is empty.
  • For every non-zero i, cv3_i is the union of cv1_i and cv2_i.
  • If P1_i or P2_i is “array of unknown bound of”, P3_i is “array of unknown bound of”, otherwise it is P1_i.
  • If cv3_i is different from cv1_i or cv2_i, or P3_i is different from P1_i or P2_i, then const is added to cv3_k for every k in [1i).

A prvalue of type T1 can be converted to type T2 if the qualification-combined type of T1 and T2 is cv-unqualified T2.

(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 = const char**;

// 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()
{
    const char 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++
const char* const * p2 = p; // error in C, OK in C++

Function pointer conversions

  • A prvalue of type pointer to non-throwing function can be converted to a prvalue pointer to potentially-throwing function.
  • A prvalue of type pointer to non-throwing member function can be converted to a prvalue pointer to potentially-throwing member function.
void (*p)();
void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function

struct S
{
    typedef void (*p)();
    operator p();
};
void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function
(since C++17)

The safe bool problem

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 as T::operator bool() const;, the implicit conversion sequence allowed one additional standard conversion sequence after that function call, which means the resultant bool could be converted to int, allowing such code as obj << 1; or int i = obj;.

One early solution for this can be seen in std::basic_ios, which initially defines operator void*, so that the code such as if (std::cin) {...} compiles because void* is convertible to bool, but int n = std::cout; does not compile because void* is not convertible to int. This still allows nonsense code such as delete std::cout; to compile.

Many pre-C++11 third party libraries were designed with a more elaborate solution, known as the Safe Bool idiom. std::basic_ios also allowed this idiom via LWG issue 468, and operator void* was replaced (see notes).

Since C++11, explicit bool conversion can also be used to resolve the safe bool problem.

Defect reports

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 from double* const (*p)[3]
to double const * 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
indeterminate unsigned char
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 to bool
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 to bool 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
unsigned char 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 and char16_t had different integral
promotion strategies, but they can fit both of them
char8_t should be promoted
in the same way as char16_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 an unsigned int
lvalue referring to an int object with value -1 was unclear
made clear

See also

C documentation for Implicit conversions