библиотека — типы общего назначенияlibrary — general-purpose types
enum class поверх unsigned char, представляющий сырой байт памяти — без арифметики +/- и без неявных преобразований в/из целочисленных и символьных типов.An enum class over unsigned char representing a raw memory byte — no +/- arithmetic, no implicit conversions to/from integer or character types.
std::byte (заголовок <cstddef>) — enum class с единственным нижележащим типом unsigned char, назначение которого — представлять "сырой байт памяти" как отдельную концепцию, отличную от числа и от символа. У него определены только побитовые операторы (|, &, ^, ~, <<, >> и их составные версии) — арифметических +/- нет вообще, и нет неявного преобразования в/из int, char или любого другого целочисленного типа.std::byte (header <cstddef>) is an enum class with a single underlying type, unsigned char, whose purpose is to represent "a raw memory byte" as a concept distinct from a number and from a character. It only has bitwise operators defined (|, &, ^, ~, <<, >>, and their compound-assignment forms) — there's no +/- arithmetic at all, and no implicit conversion to/from int, char, or any other integer type.
unsigned char b = 0xFF;
b = b + 1; // компилируется — но что значит "прибавить 1 к байту памяти"?// compiles — but what does "add 1 to a memory byte" even mean?
char c = b; // неявно "стал символом" — тоже компилируется без предупреждений// implicitly "became a character" — also compiles without warnings
printf("%c", b); // байт памяти напечатан как текстовый символ — вряд ли задумывалось так// a memory byte printed as a text character — probably not the intent
std::byte b{0xFF};
b = b & std::byte{0x0F}; // только побитовые операции — то, для чего байт и нужен// only bitwise operations — exactly what a byte is for
// b = b + 1; — ошибка компиляции, арифметики нет// b = b + 1; — compile error, no arithmetic exists
// char c = b; — ошибка компиляции, нет неявного преобразования// char c = b; — compile error, no implicit conversion
int v = std::to_integer<int>(b); // явно, только так можно получить число// explicit — the only way to get a number out
Один и тот же тип использовался одновременно как маленькое целое число (арифметика, диапазон 0-255), как единица текста (символ строки, локаль, кодировка) и как сырой байт памяти (буферы, сериализация, побитовые операции). Эти три роли концептуально не связаны, но компилятор не различал их — любая операция, законная для одной роли, молча разрешалась и для двух других.The same type was used simultaneously as a small integer (arithmetic, range 0-255), as a unit of text (a string's character, locale, encoding), and as a raw memory byte (buffers, serialization, bitwise operations). These three roles are conceptually unrelated, but the compiler didn't distinguish between them — any operation legal for one role was silently allowed for the other two as well.
Код, работающий с сырыми байтами буфера через unsigned char, мог случайно применить арифметику там, где имелась в виду побитовая операция, или получить неявное преобразование в char при передаче в функцию, ожидающую текст — компилятор в обоих случаях промолчит, потому что типы формально совместимы.Code working with raw buffer bytes via unsigned char could accidentally apply arithmetic where a bitwise operation was meant, or get an implicit conversion to char when passed into a function expecting text — the compiler stays silent in both cases, because the types are formally compatible.
Сделав std::byte enum class, а не typedef поверх unsigned char, комитет добился строгой типовой изоляции: компилятор теперь отклоняет на этапе компиляции именно те операции, которые для роли "сырой байт" не имеют смысла (арифметика, неявное преобразование в символ/число), оставляя только операции, действительно нужные для побитовой работы с памятью.By making std::byte an enum class rather than a typedef over unsigned char, the committee achieved strict type isolation: the compiler now rejects at compile time exactly the operations that make no sense for the "raw byte" role (arithmetic, implicit conversion to a character/number), leaving only the operations actually needed for bitwise memory work.
#include <cstddef>
// std::byte определён примерно так (упрощённо):// std::byte is defined roughly like this (simplified):
enum class byte : unsigned char {};
// инициализация — списком, как у любого enum class:// initialization — via brace-init, like any enum class:
std::byte flags{0b1010};
// побитовые операторы определены как свободные функции поверх этого enum:// bitwise operators are defined as free functions on top of this enum:
flags |= std::byte{0b0100};
flags &= std::byte{0b1111};
std::byte inv = ~flags;
std::byte shifted = flags << 2;
// единственный явный путь наружу — to_integer<T>:// the only explicit way out — to_integer<T>:
int asInt = std::to_integer<int>(flags);
// типичное применение — буферы сырой памяти:// typical use — raw memory buffers:
std::byte buffer[1024];
std::memset(buffer, 0, sizeof(buffer));
Ограниченный набор операций — не недоработка, а намеренный дизайн: если в коде вдруг понадобилось сложение над std::byte, это почти всегда сигнал, что на самом деле нужен обычный целочисленный тип, а не сырой байт памяти, и стоит пересмотреть, какой тип используется для какой роли.The restricted set of operations isn't an oversight — it's deliberate design: if code suddenly needs addition over a std::byte, that's almost always a signal that what's actually needed is an ordinary integer type, not a raw memory byte, and it's worth reconsidering which type is used for which role.
std::byte b; b = b + 1; не компилируется, и это правильное поведение: сырой байт памяти обычно не "складывают" в осмысленном смысле (в отличие от индекса или счётчика). Если тянет написать такую арифметику — вероятно, нужен int/size_t, а не std::byte, для этой конкретной переменной.std::byte b; b = b + 1; doesn't compile, and that's correct behavior: a raw memory byte usually isn't "added" in any meaningful sense (unlike an index or a counter). If the urge is to write such arithmetic, an int/size_t is probably what's needed for that particular variable, not a std::byte.
Нет способа неявно получить число из std::byte — ни static_cast<int>(b) без явной специализации, ни автоматическое преобразование в условии if (b). Единственный путь — std::to_integer<T>(b), который явно указывает, в какой целочисленный тип конвертировать значение.There's no way to implicitly get a number out of std::byte — neither static_cast<int>(b) without an explicit cast, nor automatic conversion in a condition like if (b). The only path is std::to_integer<T>(b), which explicitly states which integer type to convert the value into.
std::byte решает конкретно проблему "сырой байт памяти", а не задачи, где действительно нужен текстовый символ — попытка использовать std::byte вместо char для строк лишена смысла: отсутствие неявных преобразований и арифметики, полезное для буферов, только мешает при работе с текстом.std::byte specifically solves the "raw memory byte" problem, not tasks where an actual text character is needed — trying to use std::byte instead of char for strings makes no sense: the lack of implicit conversions and arithmetic, useful for buffers, only gets in the way when working with text.