Date: Wed, 21 Jan 2026 13:44:09 +0000
On Wed, 21 Jan 2026 at 12:57, Frederick Virchanza Gotham via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Before I begin, I realise that static_cast can cause UB with
> intrinsics, for example:
>
> char a;
> double &d = *static_cast<double*>( static_cast<void*>(&a) );
> d = 0.0;
>
These are not "intrinsics", they're fundamental types. An intrinsic is a
built-in function.
https://en.wikipedia.org/wiki/Intrinsic_function
> But in this post I'm talking specifically about classes. We can use
> 'static_cast' to convert from a derived class to a base:
>
> Base *b = static_cast<Base*>( &derived );
>
> or more simply:
>
> Base *b = &derived;
>
> If you imagine this as a UML class diagram, you'll have a box for
> Base, and then below it you'll have a box for Derived. You're
> converting from Derived to Base, so the movement is going upwards, and
> so we call it an upcast.
>
> Converting from Base to Derived is called a downcast, and it can cause UB:
>
> struct Base { int a; };
> struct Derived : Base { int b; };
> Base var;
> Derived &derived = static_cast<Derived&>( var );
> derived.b = 666;
>
> This should never have been made possible with 'static_cast' -- there
> should have been a different kind of cast operator for this purpose.
>
> When I'm using 'static_cast' with classes in my own code, in order to
> avoid a downcast, I use my own 'static_upcast' defined as follows:
>
> template<class Derived, class Base>
> concept derived_fromCV = is_base_of_v<Base, Derived> &&
> is_convertible_v<Derived*, Base*>;
>
> template<class To, class From>
> requires is_lvalue_reference_v<To> && (!is_reference_v<From>)
> && derived_fromCV< From, remove_reference_t<To> >
> [[nodiscard]] constexpr To static_upcast(From &arg) noexcept
> {
> return static_cast<To>(arg);
> }
>
> This prevents me from doing a dodgy down-cast, which is a necessary
> precaution in my implementation of chimeric_ptr. Note that I use my
> own 'derived_fromCV' instead of 'std::derived_from' to avoid a
> const/volatile violation.
>
> static_cast should never have been allowed to perform downcasts, and
> in order to deal with this issue, I think the following should happen:
>
> C++29: Using static_cast for downcasts should be marked
> deprecated, and a compiler warning should be issued wherever
> static_cast is used for purpose, and the compiler should provide the
> alternative 'static_downcast'.
> C++32: static_cast forces a compiler error when used for a
> downcast, and so you must use static_downcast
>
So you're suggesting that static_cast should only be used for explicit type
conversions and for upcasts where it's redundant.
Why are you even using it for upcasts, where it's not needed?
If you don't use it for upcasts, then 'static_cast' is the way to spell the
downcasts that you want to introduce a new keyword for.
std-proposals_at_[hidden]> wrote:
> Before I begin, I realise that static_cast can cause UB with
> intrinsics, for example:
>
> char a;
> double &d = *static_cast<double*>( static_cast<void*>(&a) );
> d = 0.0;
>
These are not "intrinsics", they're fundamental types. An intrinsic is a
built-in function.
https://en.wikipedia.org/wiki/Intrinsic_function
> But in this post I'm talking specifically about classes. We can use
> 'static_cast' to convert from a derived class to a base:
>
> Base *b = static_cast<Base*>( &derived );
>
> or more simply:
>
> Base *b = &derived;
>
> If you imagine this as a UML class diagram, you'll have a box for
> Base, and then below it you'll have a box for Derived. You're
> converting from Derived to Base, so the movement is going upwards, and
> so we call it an upcast.
>
> Converting from Base to Derived is called a downcast, and it can cause UB:
>
> struct Base { int a; };
> struct Derived : Base { int b; };
> Base var;
> Derived &derived = static_cast<Derived&>( var );
> derived.b = 666;
>
> This should never have been made possible with 'static_cast' -- there
> should have been a different kind of cast operator for this purpose.
>
> When I'm using 'static_cast' with classes in my own code, in order to
> avoid a downcast, I use my own 'static_upcast' defined as follows:
>
> template<class Derived, class Base>
> concept derived_fromCV = is_base_of_v<Base, Derived> &&
> is_convertible_v<Derived*, Base*>;
>
> template<class To, class From>
> requires is_lvalue_reference_v<To> && (!is_reference_v<From>)
> && derived_fromCV< From, remove_reference_t<To> >
> [[nodiscard]] constexpr To static_upcast(From &arg) noexcept
> {
> return static_cast<To>(arg);
> }
>
> This prevents me from doing a dodgy down-cast, which is a necessary
> precaution in my implementation of chimeric_ptr. Note that I use my
> own 'derived_fromCV' instead of 'std::derived_from' to avoid a
> const/volatile violation.
>
> static_cast should never have been allowed to perform downcasts, and
> in order to deal with this issue, I think the following should happen:
>
> C++29: Using static_cast for downcasts should be marked
> deprecated, and a compiler warning should be issued wherever
> static_cast is used for purpose, and the compiler should provide the
> alternative 'static_downcast'.
> C++32: static_cast forces a compiler error when used for a
> downcast, and so you must use static_downcast
>
So you're suggesting that static_cast should only be used for explicit type
conversions and for upcasts where it's redundant.
Why are you even using it for upcasts, where it's not needed?
If you don't use it for upcasts, then 'static_cast' is the way to spell the
downcasts that you want to introduce a new keyword for.
Received on 2026-01-21 13:44:27
