C-style casts are defined to work by basically trying a bunch of
different casts, in order, and whichever the first one is that works
is what gets done. If a C-style cast works in constexpr code, it is
*only* because it picked a `static_cast`, not a `reinterpret_cast`.
I know that, I deliberately omitted more detailed description simply to say that it should work in the same cases as C-cast does.

You're writing `constexpr` code, so you already know that it
*must* use `static_cast`, so that's what you should have written.
That's the point, `static_cast` will not work when types are for example `char` and `std::byte`.

As for just making it a non-constexpr function... no.
But that's exactly how the C-cast version behaves because it transforms to `reinterpret_cast`. When types match it's a constexpr function, otherwise it's not.

Why not use if constexpr?
Because then it's not a generic code anymore, it's a workaround around an artificial constraint. Isn't it silly that people are forced to use bad old C-cast instead of C++ construction just because something is prohibited without a reason?

On Fri, May 27, 2022 at 5:16 PM Edward Catmur <ecatmur@googlemail.com> wrote:


On Fri, 27 May 2022 at 07:59, Oleksandr Koval via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
That is, in:

template<typename To, typename From>
constexpr To cast(From p){
    return (To)p;                       // #1
    // return reinterpret_cast<To>(p);  // #2
}

line #2 should work in constexpr context in all cases where #1 works, in other cases it should be not an error but just a non-constexpr function. Note that I don't propose to silently make the function non-constexpr when it contains reinterpret_cast, this should be allowed only in generic context, when types are not known.

reinterpret_cast is generally preferred over C-cast but in some generic code reinterpret_cast doesn’t work. If you wonder about use-case, I have an array-like wrapper around memory buffer. Type of element is not always the same as the type of a buffer's byte. I want to mark my functions `constexpr` and have them actually `constexpr` only when types match.  Right now I’m forced to use C-cast just because reinterpret_cast is unconditionally forbidden even when it does no harm:

template<typename Byte, typename T>
class ArrayPtr{
    Byte* ptr;

    constexpr T* data() const noexcept{
        return (T*)ptr;
        // return reinterpret_cast<T*>(ptr); // not allowed
    }
};
 
Why not use if constexpr?

    constexpr T* data() const noexcept{
        if constexpr (std::is_constructible_v<T*, Byte*>)
            return static_cast<T*>(ptr);
        else
            return reinterpret_cast<T*>(ptr);
    }

A constexpr function is allowed to contain reinterpret_cast off the constant-evaluated path.


--
Regards,
Oleksandr Koval.