static_cast
conversion
Converts between types using a combination of implicit and user-defined conversions.
Contents |
Syntax
static_cast<
target-type
>(
expression
)
|
|||||||||
Returns a value of type target-type .
Explanation
Only the following conversions can be done with static_cast , except when such conversions would cast away constness (or volatility).
Base
” and
target-type
is “reference to
cv2
Derived
”, the result refers to the object of type
Derived
enclosing
expression
if all following conditions are satisfied:
-
Derivedis a complete class type. -
Baseis a base class ofDerived. - cv1 is not a greater cv-qualification than cv2 .
-
Baseis a virtual base class ofDerived. -
Baseis a base class of a virtual base class ofDerived. -
No valid
standard conversion
from “pointer to
Derived” to “pointer toBase” exists.
Derived
, the behavior is undefined.
struct B {}; struct D : B { B b; }; D d; B& br1 = d; B& br2 = d.b; static_cast<D&>(br1); // OK, lvalue denoting the original “d” object static_cast<D&>(br2); // UB: the “b” subobject is not a base class subobject
|
2)
If
target-type
is “rvalue reference to
Derived
” and
expression
is an xvalue of type “(possibly cv-qualified)
Base
” such that
Base
is a base class of
Derived
, the result and constraints of such a conversion are the same as those of the “
Base
lvalue to
Derived
reference” conversion.
3)
If
target-type
is an rvalue reference type and the referenced type is
reference-compatible
with the type of
expression
,
static_cast
converts the value of
glvalue, class prvalue, or array prvalue
(until C++17)
any lvalue
(since C++17)
expression
to xvalue referring to the same object as the expression, or to its base class subobject (depending on
target-type
).
[1]
If
target-type
is an inaccessible or ambiguous base of the type of
expression
, the program is ill-formed.
|
(since C++11) |
|
the declaration target-type temp ( expression ) ; is well-formed for some invented temporary variable temp . The effect of such an explicit conversion is the same as performing the declaration and initialization and then using temp as the result of the conversion. The expression is used as an lvalue (until C++11) a glvalue (since C++11) if and only if the initialization uses it as an lvalue (until C++11) a glvalue (since C++11) . |
(until C++17) | ||
|
any of the following conditions is satisfied:
The explicit conversion is defined as follows:
|
(since C++17) |
- lvalue-to-rvalue conversion
- array-to-pointer conversion
- function-to-pointer conversion
- null pointer conversion
- null member pointer conversion
- boolean conversion
| (since C++17) |
|
a)
A value of
scoped enumeration
type can be converted to an integer or floating-point type.
|
(since C++11) |
- If target-type has a fixed underlying type, expression is first converted to that type by integral promotion or integral conversion , if necessary, and then to target-type .
- If target-type does not have a fixed underlying type, the value of expression is unchanged if the original value is within the range of the enumeration values , otherwise the behavior is undefined.
|
d)
A prvalue of floating-point type can be explicitly converted to any other floating-point type.
|
(since C++23) |
Base
” can be explicitly converted to the type “pointer to
cv2
Derived
” if all following conditions are satisfied:
-
Derivedis a complete class type. -
Baseis a base class ofDerived. - cv1 is not a greater cv-qualification than cv2 .
Derived
enclosing the object of type
Base
pointed to by
expression
.
-
Baseis a virtual base class ofDerived. -
Baseis a base class of a virtual base class ofDerived. -
No valid standard conversion from “pointer to
Derived” to “pointer toBase” exists.
Derived
, the behavior is undefined.
Derived
of type
cv1
T
” can be explicitly converted to the type “pointer to member of
Base
of type
cv2
T
” if all following conditions are satisfied:
-
Derivedis a complete class type. -
Baseis a base class ofDerived. - cv1 is not a greater cv-qualification than cv2 .
Base
.
Base
of type
T
” to “pointer to member of
Derived
of type
T
” exists, the program is ill-formed.
Base
, the behavior is undefined.
T
” if
T
is an object type and
cv1
is not a greater cv-qualification than
cv2
.
|
(until C++17) |
|
(since C++17) |
As with all cast expressions, the result is:
- an lvalue if target-type is an lvalue reference type or an rvalue reference to function type (since C++11) ;
|
(since C++11) |
- a prvalue otherwise.
- ↑ This type of static_cast is used to implement move semantics in std::move .
- ↑ If IEEE arithmetic is supported, rounding defaults to nearest.
Pointer-interconvertible objects
Two objects a and b are pointer-interconvertible if:
- they are the same object, or
- one is a union object and the other is a non-static data member of that object, or
- one is a standard-layout class object and the other is the first non-static data member of that object or any base class subobject of that object, or
- there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.
union U { int a; double b; } u; void* x = &u; // x's value is “pointer to u” double* y = static_cast<double*>(x); // y's value is “pointer to u.b” char* z = static_cast<char*>(x); // z's value is “pointer to u”
Notes
Base-to-derived conversions (
downcasts
) using
static_cast
make no runtime checks to ensure that the
dynamic type
of the pointed/referred object is
Derived
, and may only be used safely if this precondition is guaranteed by other means, such as when implementing
static polymorphism
. Safe downcast may be done with
dynamic_cast
.
static_cast may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type, as in
std::for_each(files.begin(), files.end(), static_cast<std::ostream&(*)(std::ostream&)>(std::flush));
Keywords
Example
#include <iostream> #include <vector> struct B { int m = 42; const char* hello() const { return "Hello world, this is B!\n"; } }; struct D : B { const char* hello() const { return "Hello world, this is D!\n"; } }; enum class E { ONE = 1, TWO, THREE }; enum EU { ONE = 1, TWO, THREE }; int main() { // 1. static downcast D d; B& br = d; // upcast via implicit conversion std::cout << "1) " << br.hello(); D& another_d = static_cast<D&>(br); // downcast std::cout << "1) " << another_d.hello(); // 3. lvalue to xvalue std::vector<int> v0{1, 2, 3}; std::vector<int> v2 = static_cast<std::vector<int>&&>(v0); std::cout << "3) after move, v0.size() = " << v0.size() << '\n'; // 4. discarded-value expression static_cast<void>(v2.size()); // 5. initializing conversion int n = static_cast<int>(3.14); std::cout << "5) n = " << n << '\n'; std::vector<int> v = static_cast<std::vector<int>>(10); std::cout << "5) v.size() = " << v.size() << '\n'; // 6. inverse of implicit conversion void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "6) *ni = " << *ni << '\n'; // 7a. scoped enum to int E e = E::TWO; int two = static_cast<int>(e); std::cout << "7a) " << two << '\n'; // 7b. int to enum, enum to another enum E e2 = static_cast<E>(two); [[maybe_unused]] EU eu = static_cast<EU>(e2); // 7f. pointer to member upcast int D::*pm = &D::m; std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n'; // 7g. void* to any object pointer void* voidp = &e; [[maybe_unused]] std::vector<int>* p = static_cast<std::vector<int>*>(voidp); }
Output:
1) Hello world, this is B! 1) Hello world, this is D! 3) after move, v0.size() = 0 5) n = 3 5) v.size() = 10 6) *ni = 3 7a) 2 7f) 42
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 137 | C++98 |
the constness and volatility of
pointers to void could be casted away |
cv-qualifications cannot be
casted away in such cases |
| CWG 427 | C++98 | downcast might be ambiguous with direct-initialization | selects downcast in this case |
| CWG 439 | C++98 |
when converting a “pointer to object” to “pointer to
void ” then back to itself, it could only preserve its value if the result type has the same cv-qualification |
cv-qualification
may be different |
| CWG 1094 | C++98 |
the conversion from floating-point values
to enumeration values was unspecified |
specified |
| CWG 1320 | C++11 |
the conversion from scoped enumeration
values to bool was unspecified |
specified |
| CWG 1412 | C++98 |
the result of the conversion from
“pointer to void ” to “pointer to object” was unclear |
made clear |
| CWG 1447 | C++11 |
the conversion from bit-fields to rvalue references
was unspecified (cannot bind references to bit-fields) |
specified |
| CWG 1766 | C++98 |
the conversion from integral or enumeration values to enumeration
values yielded unspecified result if expression is out of range |
the behavior is
undefined in this case |
| CWG 1832 | C++98 |
the conversion from integral or enumeration values to
enumeration values allowed target-type to be incomplete |
not allowed |
| CWG 2224 | C++98 |
the conversion from a member of base class type to
its complete object of derived class type was valid |
the behavior is
undefined in this case |
| CWG 2254 | C++11 |
a standard-layout class object with no data members
was pointer-interconvertible to its first base class |
it is pointer-interconvertible
to any of its base classes |
| CWG 2284 | C++11 |
a non-standard-layout union object and a non-static data
member of that object were not pointer-interconvertible |
they are |
| CWG 2310 | C++98 |
for base-to-derived pointer conversions and
derived-to-base pointer-to-member conversions, the derived class type could be incomplete |
must be complete |
| CWG 2338 | C++11 |
the conversion to enumeration types with fixed underlying type
resulted in undefined behavior if expression is out of range |
convert to the underlying type
first (no undefined behavior) |
| CWG 2499 | C++11 |
a standard-layout class might have a non-pointer-interconvertible
base class, even though all base subobjects have the same address |
it does not have |
| CWG 2718 | C++98 |
for base-to-derived reference conversions,
the derived class type could be incomplete |
must be complete |
| CWG 2882 | C++98 |
it was unclear whether
static_cast
<
void
>
(
expr
)
attempts
to form an implicit conversion sequence from expr to void |
no attempt in this case |
References
- C++23 standard (ISO/IEC 14882:2024):
-
- 7.6.1.9 Static cast [expr.static.cast]
- C++20 standard (ISO/IEC 14882:2020):
-
- 7.6.1.8 Static cast [expr.static.cast]
- C++17 standard (ISO/IEC 14882:2017):
-
- 8.2.9 Static cast [expr.static.cast]
- C++14 standard (ISO/IEC 14882:2014):
-
- 5.2.9 Static cast [expr.static.cast]
- C++11 standard (ISO/IEC 14882:2011):
-
- 5.2.9 Static cast [expr.static.cast]
- C++98 standard (ISO/IEC 14882:1998):
-
- 5.2.9 Static cast [expr.static.cast]
- C++03 standard (ISO/IEC 14882:2003):
-
- 5.2.9 Static cast [expr.static.cast]