【问题标题】:Are bit flags an intended use of std::byte?位标志是 std::byte 的预期用途吗?
【发布时间】:2019-08-29 21:33:40
【问题描述】:

从 C++17 开始,有以下类型表示 8 位存储单元:

  1. 字符,无符号字符
  2. int8_t, uint8_t
  3. std::byte

据我了解,其意图是现在应该在字节实际表示字符时使用字符,例如,在字符串中。当字节表示的数值恰好是整数,只需要 8 位存储空间时,应使用 int8_t。并且 std::byte 应该用于其他所有内容,本质上是作为二进制数据的单位——比如说,如果你从文件系统中读取二进制文件。

但是位域呢?位标志...无论您想如何称呼它们。就像说您正在编写一个随机迷宫生成器,并且您希望将迷宫表示为一个 std::vector 字节,其中每个字节包含标志作为指定单元格的哪些墙存在的位。如果您想在 bool 结构和此类单元格的字节表示之间来回转换,您将不得不使用类似于以下语法的东西,我称之为 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});
}

这种语法对我来说似乎有点冗长,必须显式转换为 bool,没有 std::byte{0} 的短文字等。

这种事情有一些更简单的语法还是 std::byte 是错误的类型选择?

【问题讨论】:

  • “一个只需要 8 位存储的整数”将是 std::int_least8_t 或 std::int_fast8_t。如果硬件没有 8 位类型,std::int8_t 不存在。

标签: c++ c++17


【解决方案1】:

就像说你正在编写一个随机迷宫生成器,并且你想将迷宫表示为一个 std::vector 字节,其中每个字节都包含标志,作为指定单元格的哪些墙存在的位。

考虑为此使用std::vector 或std::bitset&lt;4&gt;。您可以通过其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());
}

【讨论】:

    【解决方案2】:

    为什么不对位使用位域?

    struct Cell
       unsigned top : 1;
       unsigned bottom : 1;
       unsigned left : 1;
       unsigned right : 1;
    };
    

    【讨论】:

      猜你喜欢
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 2010-11-27
      相关资源
      最近更新 更多