static_cast conversion

Converts between types using a combination of implicit and user-defined conversions.

# 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

# 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);
}

# Defect reports

DRApplied toBehavior as publishedCorrect behavior
CWG 137C++98the constness and volatility ofpointers to void could be casted awaycv-qualifications cannot becasted away in such cases
CWG 427C++98downcast might be ambiguous with direct-initializationselects downcast in this case
CWG 439C++98when converting a “pointer to object” to “pointer tovoid” then back to itself, it could only preserve itsvalue if the result type has the same cv-qualificationcv-qualificationmay be different
CWG 1094C++98the conversion from floating-point valuesto enumeration values was unspecifiedspecified
CWG 1320C++11the conversion from scoped enumerationvalues to bool was unspecifiedspecified
CWG 1412C++98the result of the conversion from“pointer tovoid” to “pointer to object” was unclearmade clear
CWG 1447C++11the conversion from bit-fields to rvalue referenceswas unspecified (cannot bind references to bit-fields)specified
CWG 1766C++98the conversion from integral or enumeration values to enumerationvalues yielded unspecified result if expression is out of rangethe behavior isundefined in this case
CWG 1832C++98the conversion from integral or enumeration values toenumeration values allowed target-type to be incompletenot allowed
CWG 2224C++98the conversion from a member of base class type toits complete object of derived class type was validthe behavior isundefined in this case
CWG 2254C++11a standard-layout class object with no data memberswas pointer-interconvertible to its first base classit is pointer-interconvertibleto any of its base classes
CWG 2284C++11a non-standard-layout union object and a non-static datamember of that object were not pointer-interconvertiblethey are
CWG 2310C++98for base-to-derived pointer conversions andderived-to-base pointer-to-member conversions,the derived class type could be incompletemust be complete
CWG 2338C++11the conversion to enumeration types with fixed underlying typeresulted in undefined behavior if expression is out of rangeconvert to the underlying typefirst (no undefined behavior)
CWG 2499C++11a standard-layout class might have a non-pointer-interconvertiblebase class, even though all base subobjects have the same addressit does not have
CWG 2718C++98for base-to-derived reference conversions,the derived class type could be incompletemust be complete
CWG 2882C++98it was unclear whether static_cast(expr) attemptsto form an implicit conversion sequence from expr to voidno attempt in this case

# See also