Implicit conversions
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
, includingreturn
statement in a function returningT2
. - 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.
Contents |
[edit] Order of the conversions
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 built-in type to another built-in type, only one standard conversion sequence is allowed.
A standard conversion sequence consists of the following, in this order:
A user-defined conversion consists of:
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.
One exception is the above rule is the special implicit conversion invoked in the following five contexts (since C++11), where type bool is expected:
-
- controlling expression of
if
,while
,for
- the logical operators
!
,&&
and||
- the conditional operator
?:
-
static_assert
-
noexcept
- controlling expression of
in such contexts, implicit conversion sequence is built if the declaration bool t(e); is well-formed. that is, the explicit user-defined conversion function such as explicit T::operator bool() const;
is considered. Such expression e
is said to be contextually convertible to bool.
[edit] Lvalue transformations
Lvalue transformations are applied when lvalue argument (e.g. reference to an object) is used in context where rvalue (e.g. a number) is expected.
[edit] Lvalue to rvalue conversion
A glvalue of any non-function, non-array type T
can be implicitly converted to prvalue of the same type. If T
is a non-class type, this conversion also removes cv-qualifiers. Unless encountered in unevaluated context (in an operand of sizeof, typeid, noexcept, or decltype), this conversion effectively copy-constructs a temporary object of type T
using the original glvalue as the constructor argument, and that temporary object is returned as a prvalue. If the glvalue has the type std::nullptr_t, the resulting prvalue is the null pointer constant nullptr
.
[edit] Array to pointer conversion
A 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
". The resulting pointer refers to the first element of the array.
[edit] Function to pointer
An lvalue of function type T
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.
[edit] Numeric promotions
[edit] Integral promotion
Prvalues of small integral types (such as char) 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. This conversion always preserves the value.
The following implicit conversions are classified as integral promotions:
-
-
signed char
orsigned short
can be converted to int.
-
-
-
unsigned char
orunsigned short
can be converted to unsigned int.
-
-
-
char
can be converted to int or unsigned int depending on the underlying type: signed char or unsigned char (see above)
-
-
-
wchar_t
,char16_t
, andchar32_t
can be converted to the first type from the following list able to hold their entire value range: int, unsigned int, long, unsigned long, long long, unsigned long long.
-
-
- An unscoped 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: int, unsigned int, long, unsigned long, long long, or unsigned long long. If the value range is greater, no integral promotions apply.
-
- An unscoped enumeration type whose underlying type is fixed can be converted to its promoted underlying type. (since C++11)
-
- A bitfield type can be converted to int if it can represent entire value range of the bitfield, otherwise to unsigned int if it can represent entire value range of the bitfield, otherwise no integral promotions apply.
-
- The type bool can be converted to int with the value false becoming 0 and true becoming 1.
[edit] Floating point promotion
A prvalue of type float can be converted to prvalue of type double. The value does not change.
[edit] Numeric conversions
Unlike the promotions, numeric conversions may change the values, with potential loss of precision.
[edit] 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 value modulo 2n
where n is the number of bits used to represent the destination type. In 2's complement arithmetic (used on all platforms where C++ compilers are available), this conversion is a no-op, except for the truncation if the destination type is to small.
- If the destination type is unsigned, the resulting value is the value modulo 2n
-
- 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.
-
- 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)
[edit] Floating point conversions
A prvalue of an floating-point type can be converted to prvalue of any other floating-point type. 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)
-
- Otherwise, the behavior is undefined.
[edit] Floating - integral conversions
-
- A prvalue of floating-point type can be converted to prvalue of any integer type. The fractional part is truncated, that is, the fractional part is discarded. If the value can not fit into the destination type, the behavior is undefined. 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 prvalue of any floating-point type. If the value can not be represented correctly, it is implementation defined whether the closest higher or the closest lower representable value will be selected. If the value can not 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.
[edit] Pointer conversions
-
- The null pointer constant NULL or any other prvalue of integral type that evaluates to zero or any prvalue of type std::nullptr_t, including the null pointer literal nullptr, 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 prvalue pointer to any (optionally cv-qualified) object type
T
can be converted to a prvalue pointer to (identically cv-qualified) void. IfT
is not the runtime type of the pointed-to object, the resulting pointer is adjusted to point to the start of the storage occupied by the most-derived object. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.
- A prvalue pointer to any (optionally cv-qualified) object type
-
- A prvalue pointer to a (optionally cv-qualified) derived class type can be converted to prvalue pointer to its accessible, unambiguous (identically cv-qualified) base class. 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.
[edit] Pointer-to-member conversions
-
- The null pointer constant NULL or any other prvalue of integral type that evaluates to zero or any prvalue of type std::nullptr_t, including the null pointer literal nullptr, can be converted to any pointer-to-member type, and the result is the null pointer value of that type. Such conversion (known as null pointer conversion is allowed to conver tot a cv-qualified type as a single conversion, that is, it's not considered a combination of numeric and qualifying conversions).
-
- Prvalue pointer to member of some type
T
in a base classB
can be converted to prvalue pointer to member of the same typeT
in its derived classD
. IfB
is inaccessible, ambiguous, or virtual base ofD
or is a base of some intermediate virtual base ofD
, the conversion is ill-formed (won't compile). The resulting pointer can be dereferenced with aD
object, and it will access the member within theB
base subobject of thatD
object. The null pointer value is converted to the null pointer value of the destination type.
- Prvalue pointer to member of some type
[edit] Boolean conversions
Prvalues of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to prvalues 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.
Prvalue of type std::nullptr_t, including nullptr
, can be converted to prvalue of type bool. The resulting value is false. (since C++11)
[edit] Qualification conversions
-
- A prvalue of type pointer to cv-qualified type
T
can be converted to prvalue pointer to a more cv-qualified same typeT
(in other words, constness can be added)
- A prvalue of type pointer to cv-qualified type
-
- A prvalue of type pointer to member of cv-qualified type
T
in classX
can be converted to prvalue pointer to member of more cv-qualified typeT
in classX
.
- A prvalue of type pointer to member of cv-qualified type
"More" cv-qualified means that
-
- unqualified type can be converted to
const
- unqualified type can be converted to
volatile
- unqualified type can be converted to
const volatile
-
const
type can be converted toconst volatile
-
volatile
type can be converted toconst volatile
- unqualified type can be converted to
For multi-level pointers, the following restrictions apply:
A multilevel pointer P1
which is cv1
0-qualified pointer to cv1
1-qualified pointer to ... cv1
n-1-qualified pointer to cv1
n-qualified T
is convertible to a multilevel pointer P1
which is cv2
0-qualified pointer to cv2
1-qualified pointer to ... cv2
n-1-qualified pointer to cv2
n-qualified T
only if
-
- The number of levels
n
is the same for both pointers - If there is a const in the cv1
k qualification at some level (other than level zero) of P1, there is a const in the same level cv2
k of P2 - If there is a volatile in the cv1
k qualification at some level (other than level zero) of P1, there is a volatile in the same cv2
klevel of P2 - If at some level
k
the cv-qualifications are different betweenP1
andP2
, then there must be a const at every single level (other than level zero) ofP2
up until k: cv2
1, cv2
2 ... cv2
k. - Same rules apply to multi-level pointers to members and multi-level mixed pointers to objects and pointers to members.
- Level zero is addressed by the rules for non-multilevel qualification conversions.
- The number of levels
In particular, this forbids the conversion from T**
to const T**
, but conversion to const T* const*
is allowed.
[edit] 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. 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 defines operator! and operator void*()(until C++11), 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, and many pre-C++11 third party libraries were designed with a more elaborate solution, known as the Safe Bool idiom.