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
;T2
is integral type);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.
[edit] Order of the conversionsImplicit 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:
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.
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.
!
, &&
and ||
;?:
;static_assert
declaration;noexcept
specifier;explicit
specifier;In the following contexts, a context-specific type T
is expected, and the expression e of class type E
is only allowed if
E
has a single non-explicit(since C++11) user-defined conversion function to an allowable 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
, andT
.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 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) }[edit] 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:
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):
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
.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:
sizeof
, the value contained in obj is not accessed, since that operator does not evaluate its operand.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.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.T
is a class type: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.This conversion models the act of reading a value from a memory location into a CPU register.
[edit] 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).
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 materializationA 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) [edit] Integral promotionprvalues 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).
[edit] Promotion from integral typesA 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:
If
valis the result of an lvalue-to-rvalue conversion applied to a
bit-field,
Otherwise (
valis not converted from a bit-field),
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);T
is lower than the rank of int:T
;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),
valcan be converted to a prvalue of the first of the following types that can represent all the values of its underlying type:
T
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:
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) [edit] Floating-point promotionA 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.
[edit] Numeric conversionsUnlike the promotions, numeric conversions may change the values, with potential loss of precision.
[edit] Integral conversionsA 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 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.
If the conversion is listed under floating-point promotions, it is a promotion and not a conversion.
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.
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.
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.
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.
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.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.
Derived
does not contain the original member and is not a base class of the class containing the original member, the behavior is undefined.Derived
object, and it will access the member within the Base
base subobject of that Derived
object.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) [edit] Qualification conversionsGenerally speaking:
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
.The formal definition of âqualification conversionâ is given below.
[edit] Similar typesInformally, two types are similar if, ignoring top-level cv-qualification:
For example:
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
cv_i
is a set of const and volatile, andP_i
isC_i
of typeâ,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:
U
are the same.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.[edit] 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.cv1_i
, then const is also in cv2_i
, and similarly for volatile.cv1_i
and cv2_i
are different, then const is in cv2_k
for every k in [
1,
i)
.The qualification-combined type of two types T1
and T2
is a type T3
similar to T1
such that
cv3_0
is empty,cv3_i
is the union of cv1_i
and cv2_i
, andcv3_i
is different from cv1_i
or c2_i
, then const is added to cv3_k
for every k in [
1,
i)
.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.cv3_i
is the union of cv1_i
and cv2_i
.P1_i
or P2_i
is âarray of unknown bound ofâ, P3_i
is âarray of unknown bound ofâ, otherwise it is P1_i
.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 [
1,
i)
.A prvalue of type T1
can be converted to type T2
if the qualification-combined type of T1
and T2
is cv-unqualified T2
.
// 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
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) [edit] 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.
[edit] Defect reportsThe 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 unclearRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4