Date: Fri, 16 Jan 2026 14:03:37 +0000
I think it would be a foot gun if:
T1 A {};
T2 B = std::bit_cast<T2>(A);
static_assert(sizeof(T1) == sizeof(T2));
static_assert(alignof(T1) == alignof (T2));
assert(memcmp(&A, &B, sizeof(T1) ) !=0 );
It would violate the essential contract of what `std::bit_cast` is used for.
There might be an argument to be made that casting between types with a different layout of padding bits might not be a good idea.
But I wouldn’t go around changing behavior like this.
My 2cents.
From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf Of Jan Schultke via Std-Proposals
Sent: Friday, January 16, 2026 08:50
To: C++ Proposals <std-proposals_at_[hidden].org>
Cc: Jan Schultke <janschultke_at_[hidden]>
Subject: [std-proposals] Fixing std::bit_cast padding bit issues
Hi, there are two issues with std::bit_cast, and I'd like to open a discussion for how to address these.
1. There are forms of std::bit_cast that always have undefined behavior but are well-formed, making it equivalent to std::unreachable(). For example, given struct empty{} x, std::bit_cast<char8_t>(x) always has undefined behavior because the padding bits of empty would become indeterminate bits of char8_t. I'm not entirely sure how difficult it is to diagnose the condition for this, but it seems vaguely doable with reflection.
2. It would be useful if you could obtain a result with padding bits turned into zero bits. For example, converting between integers and floating-point types is part and parcel of implementing numerical functions, but std::bit_cast<__int128>(0.0L) has undefined behavior when long double is an 80-bit x87 floating-point type (which is padded to 16 bytes). It seems implementable to have a form of std::bit_cast that converts padding bits in the source into zero bits in the destination.
These two issues are closely related. The padding-wipe behavior can be added to std::bit_cast mostly without cost to existing code because the padding-wipe only happens where currently, std::bit_cast maps padding bits in the source onto non-padding bits in the destination. However, cost is added when casting to e.g. an array of bytes; in that case, the bytes become indeterminate and the behavior is well-defined.
This presents us with a few options:
1. Make std::bit_cast ill-formed in the degenerate case, and possibly add another std::bit_cast_zero_padding function which wipes padding.
2. Make std::bit_cast wipe padding, and possibly add another function with the current behavior so that you can cheaply cast to byte arrays.
3. Keep the degenerate case as is, making std::bit_cast an alternative spelling of std::unreachable in some cases.
I think I prefer the second option, i.e. changing the behavior of std::bit_cast to wipe padding, and adding another std::bit_cast_indeterminate_padding function for the highly exotic case where you bit-cast to byte arrays and cannot afford the cost of having some of the bytes zeroed. This is spiritually similar to making variables erroneous by default, and offering the [[indeterminate]] opt-out.
T1 A {};
T2 B = std::bit_cast<T2>(A);
static_assert(sizeof(T1) == sizeof(T2));
static_assert(alignof(T1) == alignof (T2));
assert(memcmp(&A, &B, sizeof(T1) ) !=0 );
It would violate the essential contract of what `std::bit_cast` is used for.
There might be an argument to be made that casting between types with a different layout of padding bits might not be a good idea.
But I wouldn’t go around changing behavior like this.
My 2cents.
From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf Of Jan Schultke via Std-Proposals
Sent: Friday, January 16, 2026 08:50
To: C++ Proposals <std-proposals_at_[hidden].org>
Cc: Jan Schultke <janschultke_at_[hidden]>
Subject: [std-proposals] Fixing std::bit_cast padding bit issues
Hi, there are two issues with std::bit_cast, and I'd like to open a discussion for how to address these.
1. There are forms of std::bit_cast that always have undefined behavior but are well-formed, making it equivalent to std::unreachable(). For example, given struct empty{} x, std::bit_cast<char8_t>(x) always has undefined behavior because the padding bits of empty would become indeterminate bits of char8_t. I'm not entirely sure how difficult it is to diagnose the condition for this, but it seems vaguely doable with reflection.
2. It would be useful if you could obtain a result with padding bits turned into zero bits. For example, converting between integers and floating-point types is part and parcel of implementing numerical functions, but std::bit_cast<__int128>(0.0L) has undefined behavior when long double is an 80-bit x87 floating-point type (which is padded to 16 bytes). It seems implementable to have a form of std::bit_cast that converts padding bits in the source into zero bits in the destination.
These two issues are closely related. The padding-wipe behavior can be added to std::bit_cast mostly without cost to existing code because the padding-wipe only happens where currently, std::bit_cast maps padding bits in the source onto non-padding bits in the destination. However, cost is added when casting to e.g. an array of bytes; in that case, the bytes become indeterminate and the behavior is well-defined.
This presents us with a few options:
1. Make std::bit_cast ill-formed in the degenerate case, and possibly add another std::bit_cast_zero_padding function which wipes padding.
2. Make std::bit_cast wipe padding, and possibly add another function with the current behavior so that you can cheaply cast to byte arrays.
3. Keep the degenerate case as is, making std::bit_cast an alternative spelling of std::unreachable in some cases.
I think I prefer the second option, i.e. changing the behavior of std::bit_cast to wipe padding, and adding another std::bit_cast_indeterminate_padding function for the highly exotic case where you bit-cast to byte arrays and cannot afford the cost of having some of the bytes zeroed. This is spiritually similar to making variables erroneous by default, and offering the [[indeterminate]] opt-out.
Received on 2026-01-16 14:03:41
