Reputation: 9525
As of C++17 there are the following types representing an 8-bit unit of storage:
As I understand it the intent is that char's should now be used when the byte is actually representing a character, for example, in a string. int8_t should be used when the byte is representing a numeric value that happens to be an integer only needing 8-bits of storage. And std::byte should be used for everything else, essentially as a unit of binary data -- if you read a binary file from the file system, say.
But what about bit fields? bit flags ... whatever you want to call them. Like say you are writing a random maze generator and you want to represent the maze as an std::vector of bytes where each byte contains flags as bits specifying which walls of a cell are present. If you wanted to convert back and forth between a struct of bools and byte representation of such a cell you would have to use something like the following syntax as far as I call tell:
const std::byte kTop{0b0001};
const std::byte kRight{0b0010};
const std::byte kBottom{0b0100};
const std::byte kLeft{0b1000};
Maze::Cell::Cell(std::byte b) :
top( static_cast<bool>(b & kTop) ),
right( static_cast<bool>(b & kRight) ),
bottom( static_cast<bool>( b & kBottom) ),
left( static_cast<bool>(b & kLeft) )
{
}
std::byte Maze::Cell::toByte() const
{
return (top ? kTop : std::byte{0}) |
(right ? kRight : std::byte{0}) |
(bottom ? kBottom : std::byte{0}) |
(left ? kLeft : std::byte{0});
}
This syntax seems to a little verbose to me, having to explicitly cast to bool, having no short literal for std::byte{0}, etc.
Is there some simpler syntax for this sort of thing or is std::byte the wrong choice of type?
Upvotes: 0
Views: 431
Reputation: 595981
Like say you are writing a random maze generator and you want to represent the maze as an std::vector of bytes where each byte contains flags as bits specifying which walls of a cell are present.
Consider using a std::vector
of std::bitset<4>
for that. You can access the individual bits using normal array syntax via its operator[]
:
#include <bitset>
using wallSet = std::bitset<4>;
const std::size_t kTop = 0;
const std::size_t kRight = 1;
const std::size_t kBottom = 2;
const std::size_t kLeft = 3;
struct Cell
{
wallSet walls;
Cell(wallSet);
Cell(std::byte);
bool top() const;
void top(bool);
bool right() const;
void right(bool);
bool bottom() const;
void bottom(bool);
bool left() const;
void left(bool);
std::byte toByte() const;
}
Cell::Cell(wallSet ws)
: walls(ws)
{
}
Cell::Cell(std::byte b)
: Cell(wallSet(static_cast<unsigned long>(b)))
{
}
bool Cell::top() const { return walls[kTop]; }
void Cell::top(bool value) { walls[kTop] = value; }
bool Cell::right() const { return walls[kRight]; }
void Cell::right(bool value) { walls[kRight] = value; }
bool Cell::bottom() const { return walls[kBottom]; }
void Cell::bottom(bool value) { walls[kBottom] = value; }
bool Cell::left() const { return walls[kLeft]; }
void Cell::left(bool value) { walls[kLeft] = value; }
std::byte Cell::toByte() const
{
return static_cast<std::byte>(walls.to_ulong());
}
Upvotes: 2
Reputation: 16670
Why not use bit fields for bits?
struct Cell
unsigned top : 1;
unsigned bottom : 1;
unsigned left : 1;
unsigned right : 1;
};
Upvotes: 3