Difference between revisions of "cpp/language/static cast"
(Temporarily reverted the cv-qualification restriction in item 10 as it is addressed by the general requirement, added a TODO note to address this later.) |
m (Wrapped item 7 with version box.) |
||
Line 31: | Line 31: | ||
@5@ If a {{rlp|implicit_conversion|standard conversion}} sequence from {{spar|new-type}} to the type of {{spar|expression}} exists, that does not include lvalue-to-rvalue, array-to-pointer, function-to-pointer, null pointer, null member pointer, {{rev inl|since=c++17|function pointer,}} or boolean conversion, then {{c|static_cast}} can perform the inverse of that implicit conversion. | @5@ If a {{rlp|implicit_conversion|standard conversion}} sequence from {{spar|new-type}} to the type of {{spar|expression}} exists, that does not include lvalue-to-rvalue, array-to-pointer, function-to-pointer, null pointer, null member pointer, {{rev inl|since=c++17|function pointer,}} or boolean conversion, then {{c|static_cast}} can perform the inverse of that implicit conversion. | ||
@6@ If conversion of {{spar|expression}} to {{spar|new-type}} involves lvalue-to-rvalue, array-to-pointer, or function-to-pointer conversion, it can be performed explicitly by {{c|static_cast}}. | @6@ If conversion of {{spar|expression}} to {{spar|new-type}} involves lvalue-to-rvalue, array-to-pointer, or function-to-pointer conversion, it can be performed explicitly by {{c|static_cast}}. | ||
− | @7@ {{rlp|enum|Scoped enumeration | + | |
+ | {{rrev|since=c++11| | ||
+ | @7@ {{rlp|enum|Scoped enumeration}} type can be converted to an integer or floating-point type. | ||
{{rrev multi|rev1= | {{rrev multi|rev1= | ||
When the target type is {{c|bool}} (possibly cv-qualified), the result is {{c|false}} if the original value is zero and {{c|true}} for all other values. For the remaining integral types, the result is the value of the enum if it can be represented by the target type and unspecified otherwise. | When the target type is {{c|bool}} (possibly cv-qualified), the result is {{c|false}} if the original value is zero and {{c|true}} for all other values. For the remaining integral types, the result is the value of the enum if it can be represented by the target type and unspecified otherwise. | ||
|since2=c++20|rev2= | |since2=c++20|rev2= | ||
The result is the same as {{rlp|implicit conversion}} from the enum's underlying type to the destination type. | The result is the same as {{rlp|implicit conversion}} from the enum's underlying type to the destination type. | ||
+ | }} | ||
}} | }} | ||
@8@ A value of integer or enumeration type can be converted to any complete {{rlp|enum|enumeration type}}. | @8@ A value of integer or enumeration type can be converted to any complete {{rlp|enum|enumeration type}}. |
Revision as of 18:24, 9 January 2022
Converts between types using a combination of implicit and user-defined conversions.
Contents |
Syntax
static_cast < new-type > ( expression )
|
|||||||||
Returns a value of type new-type.
Explanation
This section is incomplete Reason: Put the cv-qualification requirement in each point rather than a general requirement. A user reading the items at later positions can easily ignore this restriction. |
Only the following conversions can be done with static_cast, except when such conversions would cast away constness or volatility.
>(
expression)
returns the imaginary variable Temp
initialized as if by new-type Temp(expression);
, which may involve implicit conversions, a call to the constructor of new-type or a call to a user-defined conversion operator. For non-reference new-type, the result object of the static_cast prvalue expression is what's direct-initialized.(since C++17)D
and expression is lvalue of its non-virtual base B
or prvalue pointer to it, static_cast performs a downcast. (This downcast is ill-formed if B
is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D
.) Such a downcast makes no runtime checks to ensure that the object's runtime type is actually D
, 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
.
struct B {}; struct D : B {}; D d; B& br = d; static_cast<D&>(br); // lvalue denoting the original d object
3) If new-type is an rvalue reference type, 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 sub-object (depending on new-type). If the target type is an inaccessible or ambiguous base of the type of the expression, the program is ill-formed. If the expression is a bit field lvalue, it is first converted to prvalue of the underlying type. This type of static_cast is used to implement move semantics in std::move.
|
(since C++11) |
7) Scoped enumeration type can be converted to an integer or floating-point type.
|
(since C++11) |
- If the underlying type is not fixed, the behavior is undefined if the value of expression is out of range (the range is all values possible for the smallest bit field large enough to hold all enumerators of the target enumeration).
- If the underlying type is fixed, the result is the same as converting the original value first to the underlying type of the enumeration and then to the enumeration type.
- The result is the same as converting the original value first to the underlying type of the enumeration, and then to the enumeration type.
D
can be upcast to a pointer to member of its unambiguous, accessible base class B
. This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object.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.
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, if the object has no non-static data members, 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
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 <vector> #include <iostream> struct B { int m = 0; void hello() const { std::cout << "Hello world, this is B!\n"; } }; struct D : B { void hello() const { std::cout << "Hello world, this is D!\n"; } }; enum class E { ONE = 1, TWO, THREE }; enum EU { ONE = 1, TWO, THREE }; int main() { // 1: initializing conversion int n = static_cast<int>(3.14); std::cout << "n = " << n << '\n'; std::vector<int> v = static_cast<std::vector<int>>(10); std::cout << "v.size() = " << v.size() << '\n'; // 2: static downcast D d; B& br = d; // upcast via implicit conversion br.hello(); D& another_d = static_cast<D&>(br); // downcast another_d.hello(); // 3: lvalue to xvalue std::vector<int> v2 = static_cast<std::vector<int>&&>(v); std::cout << "after move, v.size() = " << v.size() << '\n'; // 4: discarded-value expression static_cast<void>(v2.size()); // 5. inverse of implicit conversion void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "*ni = " << *ni << '\n'; // 6. array-to-pointer followed by upcast D a[10]; [[maybe_unused]] B* dp = static_cast<B*>(a); // 7. scoped enum to int or float E e = E::ONE; int one = static_cast<int>(e); std::cout << one << '\n'; // 8. int to enum, enum to another enum E e2 = static_cast<E>(one); [[maybe_unused]] EU eu = static_cast<EU>(e2); // 9. pointer to member upcast int D::*pm = &D::m; std::cout << br.*static_cast<int B::*>(pm) << '\n'; // 10. void* to any type void* voidp = &e; [[maybe_unused]] std::vector<int>* p = static_cast<std::vector<int>*>(voidp); }
Output:
n = 3 v.size() = 10 Hello world, this is B! Hello world, this is D! after move, v.size() = 0 *ni = 3 1 0
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 void pointers could be casted away |
cv-qualifications cannot be casted away in such cases |
CWG 2254 | C++11 | standard-layout class object with no data members was pointer-interconvertible to its first base class |
is pointer-interconvertible to any of its base classes |