C++ Logo

std-proposals

Advanced search

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

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Fri, 26 Jun 2026 13:52:41 +0100
On Fri, 26 Jun 2026 at 13:14, Rune Lund Olesen via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> Quick followup:
>
> If you want, I can give you all a concrete example of a generic code piece I wrote.

You haven't explained what any of this has to do with
std::is_fundamental though.


> 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 }.

That would not accept signed integer types, which is probably a good thing.

If your intention is for this to work with unsigned integer types and
std::byte, that seems pretty simple without "a lot of boilerplate
template code".

#include <concepts>
#include <cstddef>
#include <climits>

template<class R>
struct byteconcat_t {
    template<class... Arg>
    [[nodiscard]] constexpr R operator()(Arg... arg) const {
        static_assert(CHAR_BIT == 8);
        static_assert((sizeof(Arg) + ...) <= sizeof(R), "result size
of bitshift is higher than supported by return type (unsafe/possible
loss of data)");
        decltype((conv(arg) + ...)) result{};
        size_t shiftCount = (sizeof(Arg) + ...);
        ((shiftCount -= sizeof(Arg), result |= conv(arg) <<
(shiftCount * 8)), ...);
        return R(result);
    }

    static constexpr auto conv(std::unsigned_integral auto v) { return v; }
    static constexpr auto conv(std::byte b) { return (unsigned char)b; }
};

(I've also made this work with extended integer types such as unsigned
__int128_t).


> 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);
> }
> };
>

Received on 2026-06-26 12:53:00