C++ Logo

std-proposals

Advanced search

Re: [std-proposals] A better std::byte type

From: Rune Lund Olesen <rune.olesen_at_[hidden]>
Date: Fri, 26 Jun 2026 14:14:01 +0200
 Quick followup:

If you want, I can give you all a concrete example of a generic code piece
I wrote.
This can be used to obtain other types that are received in headers over a
network - eg. to synthesize some bytes into an uint16_t or uint32_t, but
also can take eg. an uint16_t and 2 uint8_t and shift them into an uint32_t.
But right now there is a big flaw in this code, mainly to allow being able
to accept std::byte(s) as input. Also I cannot easily restrict the input
arguments to integral types with static_asserts if that is what i wanted -
that would not work with std::byte as input.
The big "flaw" here is with the uintmax_t(arg) that basically allows
static_casting whatever it can into an uintmax_t - this should probably
have been the more restrictive form of uintmax_t{ arg }.
Using c++17 here, see below for the code.
And yes, all of the "problems with std::byte" can be worked around - but
this is exactly the argument I am proposing and then avoid alot of
boilerplate template code just to make std::byte work in generic code.
Otherwise std::byte is mostly suitable as an aliasing/type-puning type as
someone else wrote - and in effect not suitable to work with arbitrary data
arrays.

Have a lovely day.

Rune

//bitwise shift together into new type (and avoid implicit type promotions)
template<class R>
struct byteconcat_t {
    template<class... Arg>
    [[nodiscard]] constexpr R operator()(Arg... arg) const {
        static_assert((sizeof(Arg) + ...) <= sizeof(R), "result size of
bitshift is higher than supported by return type (unsafe/possible loss of
data)");
        uintmax_t result{};
        size_t shiftCount = (sizeof(Arg) + ...);
        ((shiftCount -= sizeof(Arg), result |= uintmax_t(arg) <<
(shiftCount * 8)), ...);
        return R(result);
    }
};


On Fri, Jun 26, 2026 at 1:59 PM Alejandro Colomar via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hi David,
>
> On 2026-06-26T11:35:13+0200, David Brown via Std-Proposals wrote:
> > My two pennies worth...
> >
> > C++ does not have a good "raw data" type that represents underlying
> memory
> > storage, and nothing else. It has a jumble of types that each do other
> > things as well, or have limitations for convenient usage as raw data.
> There
> > is a lot that is bad in all of this. But it cannot be fixed. The "best"
> > you can do is add more to the jumble, as was done with std::byte. The
> time
> > to fix it would have been 50 years ago when Ritchie thought it would be a
> > good idea if a type "char" represented character data, and raw memory
> bytes,
> > and was a small integer type.
> >
> > Unless your new "byte" type stops "unsigned char" being a byte type,
> stops
> > "void *" being a generic pointer to data, is the only type with "aliasing
> > superpowers", and is the type used in "memcpy" and everything else that
> > today uses "void *", then it would only add to the mess rather than
> fixing
> > it. And of course backwards compatibility requirements ensure that none
> of
> > those changes could possibly happen.
>
> In many decades, that could happen. After all, void* replaced char*
> back in the days.
>
> If the new _Byte* had implicit conversions like void*, and we had C's
> n3674 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3674.pdf> to
> allow implicit conversions of function pointers with similar-enough
> parameters, then backwards compatibility wouldn't be a problem.
>
> You could have void* mean something slightly different than _Byte*:
> void* is for when you want an arbitrary pointer (for example in
> qsort(3)), which will be passed to a callback function that will cast it
> back to the right type. No byte semantics are needed for that, and
> notably no pointer arithmetic.
>
> And _Byte* would be the type to implement memcpy(3):
>
> _Byte *
> memcpy(size_t n;
> _Byte dst[restrict n], const _Byte src[restrict n], size_t
> n)
> {
> for (size_t i = 0; i < n; i++)
> dst[i] = src[i];
> return dst;
> }
>
> Which would differ from void* in that it can be used to access memory,
> write to it, and do pointer arithmetic.
>
> Once n3674 is merged in C (and WG14 has already shown strong interest in
> it; we're just waiting for minor improvements to the proposal), type
> compatibility issues would entirely vanish.
>
> The remaining issue would be removing the "aliasing superpowers" from
> the character types. This is the part that will take decades. But I
> expect compilers could provide flags so that programs can already opt
> in to such semantics, declaring that they never alias anything with
> character types. Eventually, this might change to be the default, maybe
> in C5x or so, which would be nice.
>
>
> Have a lovely day!
> Alex
>
> > One thing that I think is missing, that /could/ be fixed, is raw data
> types
> > that are bigger than a byte and which have "aliasing superpowers" to
> access
> > underlying data representations. This could be achieved by standardising
> > gcc's "may_alias" type attribute - then such types could be
> "[[may_alias]]
> > uint32_t", or as an enum class or struct if preferred.
> >
> > I agree that std::byte would have (IMHO) been better without shifts or
> other
> > bitwise operations, but it is hard to remove features and I am not
> convinced
> > that adding more conversions would help.
> >
> > David
> >
> >
> >
> > On 26/06/2026 10:15, Rune Lund Olesen via Std-Proposals wrote:
> > > Thank you all for the feedback.
> > >
> > > To clarify a few points:
> > >
> > > 1. The Idea here is more to "fix" current std::byte than add new one (I
> > > wrote byte2 to not clash with current std::byte)
> > > 2. In generic code, while you can actually bitshift a std::byte, it eg.
> > > acts as an enumeration type and returns false with std::is_integral,
> > > std::is_fundamental, and so on - highlighting a few issues with using
> it
> > > with generic code
> > > 3. The idea to have a type to correctly represent "raw data" is good -
> > > it is the design or implementation if you will, that is lacking, and it
> > > should interop easier with other things (like conversions) and work
> > > better in generic code - right now it it way too restrictive and
> > > cumbersome, to the point it is prohibiting adoption.
> > >
> > > Alex, it is good to hear discussions have already been taking place.
> > >
> > > Have a lovely evening
> > >
> > > Rune Lund Olesen
> > >
> > >
> > >
> > >
> > > On Fri, Jun 26, 2026 at 12:05 AM Thiago Macieira via Std-Proposals
> <std-
> > > proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>>
> > > wrote:
> > >
> > > On Thursday, 25 June 2026 08:05:25 Pacific Daylight Time Andrey
> > > Semashev via
> > > Std-Proposals wrote:
> > > > The world has more or less settled on unsigned char/uint8_t as
> > > the type
> > > > for raw bytes
> > >
> > > unsigned char is *by definition* the byte type. uint8_t happens to
> > > also be the
> > > byte type[1] if it exists. std::byte is just an enum whose
> > > underlying type is
> > > the byte type.
> > >
> > > [1] strictly speaking, it could be another integer whose same size
> > > is the byte
> > > type, but in all implementations it's just a typedef to it.
> > >
> > > -- Thiago Macieira - thiago (AT) macieira.info
> > > <http://macieira.info> -
> > > thiago (AT) kde.org <http://kde.org>
> > > Principal Engineer - Intel Data Center - Platform & Sys. Eng.
> > > -- Std-Proposals mailing list
> > > Std-Proposals_at_[hidden] <mailto:
> Std-Proposals_at_[hidden]>
> > > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> > > <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
>
> --
> <https://www.alejandro-colomar.es>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2026-06-26 12:14:17