我可以从 uint8_t(或 std::byte)范围初始化 std::vector<bool>,以便输入中的每一位都被视为布尔值吗?

Can I initialize a std::vector<bool> from uint8_t (or std::byte) range so that every bit in input is treated as a boolean?

我知道 std::vector<bool> is bad,但我有一个非常好的用例。

我想做这样的事情:

uint8_t data [] = {7,32};
std::vector<bool> vb/*...*/ ;
// now vb is size of 8 vector with this values:
//   false, false, false, false, false, true,  true,  true, (7)
//   false, false, true, false, false,  false, false, false (32)

注意:我知道我可以手动分解输入的每个字节并进行 8 次插入,但我正在寻找标准中预构建的东西

std::vector<bool> 在这里是一个糟糕的选择,因为您正在考虑它的实现而不是它的行为....只是避免 vector<bool>.

改用 boost::dynamic_bitset。有趣的是,我个人发现它的性能要好得多:

std::array<std::uint8_t, 2> data {7,32};
boost::dynamic_bitset<std::uint8_t> vb(rbegin(data), rend(data));
std::cout << vb; // 0000011100100000

Live Demo

我们必须反转输入范围,因为 boost 的动态位集 appends 到最高有效位所在的末尾(通常是左侧),而不是右侧。

对此的建议是 P0237 基本位操作的措辞 公用事业:

#include <bit>
#include <cstdint>
std::uint8_t data [] = {7,32};
std::vector<bool> vb(
    std::bit_iterator(std::begin(data), 0)),
    std::bit_iterator(std::end(data), 0)));

有 P0237 的实现(和 N2050) called itsy

使用 容器无疑是最好的方法 - 但如果这不是一个选项,您可以创建一个迭代器类型来直接在构建时填充 vector<bool>

示例:

struct biterator {
    using value_type = bool;
    using reference = bool;
    using difference_type = std::ptrdiff_t;
    using pointer = uint8_t*;
    using iterator_category = std::forward_iterator_tag;

    biterator(const uint8_t* c) : curr(c), bit(1U<<7) {}
    biterator& operator++() { if(!(bit >>= 1)) { ++curr; bit = 1U<<7; } return *this; }
    bool operator*() const { return *curr & bit; }
    bool operator!=(const biterator& rhs) const { return curr != rhs.curr; }

private:
    const uint8_t* curr;
    uint8_t bit;
};

用法:

uint8_t data [] = {7, 32};
    
std::vector<bool> vb(biterator(std::begin(data)), biterator(std::end(data)));

Demo