C++ Logo

std-proposals

Advanced search

Re: Making bit_cast Useful

From: connor horman <chorman64_at_[hidden]>
Date: Thu, 24 Sep 2020 09:38:45 -0400
On Thu, 24 Sep 2020 at 08:51, Andrew Giese via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> * If r is an expression of type T, the expression std::bit_cast<T>(r), if
>> well-formed, shall be equivalent to copy constructing the result from r,
>> except that the expression treats copy constructors which are defined as
>> deleted as though they were defined as default instead, and does not call
>> move constructors even if r is an rvalue.
>
>
> std::bit_cast only works for types that are TriviallyCopyable, and will
> emit a compiler error otherwise. This "Reflexive" case seems perhaps
> unnecessary then.
>
> It was added for completeness. It can also be used when the copy
constructor is defined as deleted, because TriviallyCopyable allows any of
the copy constructor, move constructor, copy assignment, and move
assignment to be deleted IIRC, as long as at least one is not. Though,
you'd be right, I should mention that it's only the case if the expression
is well-formed. I've changed it to that effect.

>
> On Thu, Sep 24, 2020 at 7:13 AM connor horman via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> C++20 added the function std::bit_cast to the standard library. While the
>> result of it is defined, simply reinterpreting the bytes making up the
>> object-representation, there are actually no defined results (beyond the
>> identity case, which is simply copy-constructing the result from the
>> input). This seeks to add limitations on the results of std::bit_cast,
>> which are believed to be reasonable, and may be expected in practice.
>>
>> Reflexive:
>> (Included for completeness)
>> * If r is an expression of type T, the expression std::bit_cast<T>(r)
>> shall be equivalent to copy constructing the result from r, except that the
>> expression treats copy constructors which are defined as deleted as though
>> they were defined as default instead, and does not call move constructors
>> even if r is an rvalue.
>>
>> Enumerations and Integral types:
>> * If r is an expression of a (potentially cv-qualified) integral type
>> other than bool or an enumeration type, and U is a
>> (potentially cv-qualified) integral type other than bool or an enumeration
>> type, the expression std::bit_cast<U>(r), if well formed, shall be an
>> equivalent expression to static_cast<U>(r)
>>
>>
>> Pointer types:
>> * If r is an expression of type (potentially cv-qualified) pointer to
>> void or pointer to a character type, and U such a type, let P be the same
>> pointer type as the type or r, but with the same cv-qualifiers (ignoring
>> top-level cv-qualifiers) as U, the expression std::bit_cast<U>(r) shall be
>> well-formed and shall be an equivalent expression as
>> reinterpret_cast<U>(const_cast<P>(r))
>> * If r is an expression of type T*, and U is the same type as T ignoring
>> top level cv-qualifiers, then the expression std::bit_cast<U>(r) shall be
>> well-formed, and shall be an equivalent expression to const_cast<U*>(r)
>>
>> Pointer-interconvertible:
>> * If r is an (potentially const-qualified) lvalue, designating an object
>> a, and U is a type, such that (ignoring all top-level cv-qualifiers), there
>> is an object of type U, b, that is *pointer-interconvertible* with a,
>> then the expression std::bit_cast<U>(r), if well formed, is equivalent to
>> copy-constructing the result from a const-qualified lvalue designating b.
>>
>> Union:
>> * If r is an expression of type T, and U is a union type which has at
>> least one member of type T which is not a bitfield, if the expression
>> std::bit_cast<U>(r), if well-formed, shall yield a union where the active
>> member is the member of type T and is initialized as though by
>> std::bit_cast<T>(r). If there are multiple such members, the active member
>> is the first such member accessed by the program, or otherwise an
>> unspecified member of that type. If the union has a member of a reference
>> type, the behaviour is undefined.
>>
>> reference_wrapper:
>> * If r is an expression of type std::reference_wrapper<T>and U is
>> (possibly differently cv-qualified) T, then the expression
>> std::bit_cast<U*>(r), shall be well-formed and an equivalent expression to
>> const_cast<U*>(std::addressof(static_cast<T&>(r)))
>> * If r is an expression of type T*, which points to an object, and U is
>> (possibly differently cv-qualified) T, then the expression
>> std::bit_cast<std::reference_wrapper<U>>(r) shall be well-formed, and an
>> equivalent expression to std::ref(*const_cast<U*>(r)). If r does not point
>> to an object, the behaviour is undefined. If T is an incomplete type other
>> than (possibly cv-qualified) void or an array of unknown bound, the
>> expression treats T as though it was completed. If T is an array of unknown
>> bound, the expression treats T as though it were an array with length 1.
>>
>>
>> Unresolved Questions:
>> std::optional<std::reference_wrapper<T>> is currently not treated
>> separately. It may be nice to apply a similar pair of rules as for regular
>> std::reference_wrapper, with the additional clause that an empty optional
>> bit_casts to a null pointer and the reverse. However, unlike the
>> reference_wrapper requirements which are effective in libstdc++ and libc++
>> (because its implemented with a single raw pointer member),
>> std::optional<std::reference_wrapper<T>> is not implemented as such (though
>> libc++ interestingly implements the storage for std::optional<T&> in case
>> the standard ever decides to permit it, and this is done simply using a raw
>> pointer). A possibility is not enforcing well-formedness, but keeping the
>> behaviour if it is well-formed.
>>
>> These rules allow you to construct union values (provided the union is
>> the same size as the member). Would it be reasonable to also allow the
>> construction of Trivially Copyable, Standard Layout structure types with a
>> single member of the source type?
>>
>> None of these rules cover transitive bit casts. Would it be reasonable to
>> require such over all of these rules, or just a limited case (for example,
>> void*->reference_wrapper<char>)?
>>
>> The reference_wrapper rules don't allow void*->reference_wrapper<void>.
>> Is there a reason to allow this? Can reference_wrapper<void> exist?
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2020-09-24 08:39:00