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:
T2
as parameter; T2
; T2
, including return
statement in a function returning T2
; switch
statement (T2
is integral type); 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.
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 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.
A standard conversion sequence consists of the following, in this order:
3) zero or one function pointer conversion; | (since C++17) |
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.
In the following contexts, the type
| (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) |
| (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).
T
is any object pointer type); T
is any integral or unscoped (since C++11) enumeration type, the selected user-defined conversion function must be constexpr); switch
statement (T
is any integral or enumeration type). #include <cassert> template<typename T> class zero_init { T val; public: zero_init() : val(static_cast<T>(0)) {} zero_init(T val) : val(val) {} operator T&() { return val; } operator T() const { return val; } }; int main() { zero_init<int> i; assert(i == 0); i = 7; assert(i == 7); switch (i) {} // error until C++14 (more than one conversion function) // OK since C++14 (both functions convert to the same type int) switch (i + 0) {} // always okay (implicit conversion) }
Value transformations are conversions that change 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.
A glvalue of any non-function, non-array type T
can be implicitly converted to a prvalue of the same type. If T
is a non-class type, this conversion also removes cv-qualifiers.
The object denoted by the glvalue is not accessed if:
sizeof
, noexcept
, decltype
, (since C++11) or the static form of typeid
| (since C++11) |
If T
is a non-class type, the value contained in the object is produced as the prvalue result. For a class type, this conversion.
effectively copy-constructs a temporary object of type | (until C++17) |
converts the glvalue to a prvalue whose result object is copy-initialized by the glvalue. | (since C++17) |
This conversion models the act of reading a value from a memory location into a CPU register.
If the object to which the glvalue refers contains an indeterminate value (such as obtained by default initializing a non-class automatic variable), the behavior is undefined except if the indeterminate value is of possibly cv-qualified unsigned char
or std::byte
(since C++17) type.
The behavior is also implementation-defined (rather than undefined) if the glvalue contains a pointer value that was invalidated.
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).
Temporary materializationA prvalue of any complete type 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) |
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.
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 after lvalue-to-rvalue conversion, if applicable. This conversion always preserves the value.
The following implicit conversions are classified as integral promotions:
signed char
or signed short
can be converted to int
; unsigned char
or unsigned short
can be converted to int
if it can hold its entire value range, and unsigned int
otherwise; char
can be converted to int
or unsigned int
depending on the underlying type: signed char
or unsigned char
(see above); wchar_t
, char8_t
(since C++20), char16_t
, and char32_t
(since C++11) 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
(since C++11); int
, unsigned int
, long
, unsigned long
, long long
, or unsigned long long
, extended integer types with higher conversion rank (in rank order, signed given preference over unsigned) (since C++11). If the value range is greater, no integral promotions apply; int
if it can represent entire value range of the bit-field, otherwise to unsigned int
if it can represent entire value range of the bit-field, otherwise no integral promotions apply; bool
can be converted to int
with the value false
becoming 0
and true
becoming 1
. Note that all other conversions are not promotions; for example, overload resolution chooses char
-> int
(promotion) over char
-> short
(conversion).
A prvalue of type float
can be converted to a prvalue of type double
. The value does not change.
Unlike the promotions, numeric conversions may change the values, with potential loss of precision.
A prvalue of an integer type or of an unscoped (since C++11) 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.
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). bool
, this is a boolean conversion (see below). A prvalue of a floating-point type can be converted to a prvalue of any other floating-point type. If the conversion is listed under floating-point promotions, it is a promotion and not a conversion.
bool
, this is a boolean conversion (see below). bool
, the value false
is converted to zero, and the value true
is converted to one. 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. 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. 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. T
in a base class B
can be converted to a prvalue pointer to member of the same type T
in its derived complete class D
. If B
is inaccessible, ambiguous, or virtual base of D
or is a base of some intermediate virtual base of D
, the conversion is ill-formed (won't compile). The resulting pointer can be dereferenced with a D
object, and it will access the member within the B
base subobject of that D
object. The null pointer value is converted to the null pointer value of the destination type. A prvalue of integral, floating-point, unscoped (since C++11) 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 (since C++11) 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 | (since C++11) |
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). T
in class X
can be converted to a prvalue pointer to member of more cv-qualified type T
in class X
. "More" cv-qualified means that.
const
; volatile
; const volatile
; const
type can be converted to a pointer to const volatile
; volatile
type can be converted to a pointer to const volatile
. 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 P2
which is cv2
0-qualified pointer to cv2
1-qualified pointer to ... cv2
n-1-qualified pointer to cv2
n-qualified T
only if.
n
is the same for both pointers;
| (since C++20) |
const
in the cv1P1
, there is a const
in the same level cv2P2
; volatile
in the cv1P1
, there is a volatile
in the same cv2P2
;
| (since C++20) |
k
the P2
is more cv-qualified than P1
or there is an array type of known bound in P1
and an array type of unknown bound in P2
(since C++20), then there must be a const
at every single level (other than level zero) of P2
up until k: cv2char** p = 0; const char** p1 = p; // error: level 2 more cv-qualified but level 1 is not const const char* const * p2 = p; // OK: level 2 more cv-qualified and const added at level 1 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 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:
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
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) |
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.
The explicit bool conversion can also be used to resolve the safe bool problem. explicit operator bool() const { ... } | (since C++11) |
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 172 | C++98 | enumeration type is promoted based on its underlying type | based on its value range instead |
CWG 330 | C++98 | conversion from double * const (*p)[3] todouble const * const (*p)[3] invalid | conversion 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 is convertible to boolin both direct- and copy-initialization | direct-initialization only |
CWG 1781 | C++11 | std::nullptr_t to bool is considered a implicit conversioneven though it is only valid for direct-initialization | no longer considered an implicit conversion |
CWG 1787 | C++98 | the behavior of reading from an indeterminateunsigned char cached in a register was undefined | made well-defined |
CWG 1981 | C++11 | contextual conversions considered explicit conversion functions | not considered |
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 have different integralpromotion strategies, but they can fit both of them | char8_t should be promotedin the same way as char16_t |
C documentation for Implicit conversions |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/implicit_conversion