Skip to content

static_cast

cppreference static_cast conversion

Only the following conversions can be done with static_cast, except when such conversions would cast away constness or volatility.

NOTE: static_cast是需要维护CV的,否则会编译报错

1) implicit cast

If there is an implicit conversion sequence from expression to new_type, or if overload resolution for a direct initialization of an object or reference of type new_type from expression would find at least one viable(可行的) function, then static_cast<new_type>(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)

NOTE: 上面这段话,ifor if描述了两种情况下,static_cast的行为:new_type Temp(expression);

在Example中,有例子对此进行说明。

2) static downcast

NOTE: 在Why use static_cast(x) instead of (int)x?A中对downcast进行了说明:

The only time it's a bit risky is when you cast down to an inherited class; you must make sure that the object is actually the descendant that you claim it is, by means external to the language (like a flag in the object).

Example: CRTP

CRTP是典型的cast to derived class,下面是截取自维基百科Curiously recurring template pattern中的例子:

#include <iostream>

template<class T>
struct Base
{
    void interface()
    {
        // ...
        static_cast<T*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        T::static_sub_func();
        // ...
    }
};

struct Derived: Base<Derived>
{
    void implementation()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
    static void static_sub_func()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};
int main()
{
    Derived d;

    d.interface();
    d.static_sub_func();
}
// g++ test.cpp

上述程序的输出如下:

void Derived::implementation()
static void Derived::static_sub_func()

3) lvalue to xvalue (since C++11)

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.

gcc/libstdc++-v3/include/bits/move.h

/**
 *  @brief  Convert a value to an rvalue.
 *  @param  __t  A thing of arbitrary type.
 *  @return The parameter cast to an rvalue-reference to allow moving it.
 */
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t);}

4) discard value expression

NOTE: 关于discard value expression,参见Discarded-value-expressions 章节

5) inverse of that implicit conversion

7) enum to int or float

8) int to enum

9) pointer to member upcast

10) pointer to void to pointer to complete type

NOTE:

1、在 Sean parent Small Object Optimization for Polymorphic Types 中,对此进行了深入的讨论

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];
    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);
    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;
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}
// g++ --std=c++11 test.cpp

输出如下:

n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0

wikipedia static_cast

Examples

Question of using static_cast on “this” pointer in a derived object to base class

static_cast and explicit/implicit and user-define conversion

来源: cppreference user-defined conversion function

#include <iostream>

struct X
{
    //implicit conversion
    operator int() const
    {
        std::cout << __LINE__<< " " << __PRETTY_FUNCTION__ << std::endl;
        return 7;
    }

    // explicit conversion
    explicit operator int*() const
    {
        std::cout << __LINE__<< " " << __PRETTY_FUNCTION__ << std::endl;
        return nullptr;
    }

//   Error: array operator not allowed in conversion-type-id
//   operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const
    {
        std::cout << __LINE__<< " " << __PRETTY_FUNCTION__ << std::endl;
        return nullptr;
    } // OK if done through typedef
//  operator arr_t () const; // Error: conversion to array not allowed in any case
};

int main()
{
    X x;

    int n = static_cast<int>(x);   // OK: sets n to 7
    int m = x;                     // OK: sets m to 7

    int *p = static_cast<int*>(x);  // OK: sets p to null
//  int* q = x; // Error: no implicit conversion

    int (*pa)[3] = x;  // OK
}
// g++ --std=c++11 test.cpp

上述程序的输出如下:

8 X::operator int() const
8 X::operator int() const
15 X::operator int*() const
24 X::operator int (*)[3]() const

通过上述例子可以看出,static_cast既可以用于implicit cast,也可以用于explicit cast。