Date: Fri, 27 May 2022 17:28:02 +0300
>
> 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_at_[hidden]>
wrote:
>
>
> On Fri, 27 May 2022 at 07:59, Oleksandr Koval via Std-Proposals <
> std-proposals_at_[hidden]> 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.
>
> 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_at_[hidden]>
wrote:
>
>
> On Fri, 27 May 2022 at 07:59, Oleksandr Koval via Std-Proposals <
> std-proposals_at_[hidden]> 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.
Received on 2022-05-27 14:28:19