为什么按位或赋值运算符 |= 不能用于布尔向量?

14
如果我有一个vector<bool> vec_bool,那么我不能使用|=赋值运算符来修改向量的内容。也就是说,以下这行代码:
vec_bool[0] |= true;
vec_bool[0] |= vec_bool[1];

编译器会报错,而这些行

bool a = false;
a |= true;
a |= vec_bool[0];
vec_bool[0] = vec_bool[0] | vec_bool[1];
vec_bool[0] = vec_bool[0] || vec_bool[1];

vector<int> vec_int(3);
vec_int[0] |= vec_int[1];

不要这样做。这是什么原因呢?

gcc 给出的错误信息如下:

test.cpp:21:17: error: no match for ‘operator|=’ (operand types are ‘std::vector::reference {aka std::_Bit_reference}’ and ‘bool’)


14
请记住,std::vector<bool> 不是一种普通的向量。它不是一个实际的 bool 向量,而更像是一组位(bit)向量,其实现并未在 C++ 规范中指定。 - Some programmer dude
2
可能是为什么std :: vector <bool>没有.data()?的重复问题。 - Gaurav Sehgal
2
你可以查看 http://en.cppreference.com/w/cpp/container/vector_bool 了解更多相关信息。 - cbuchart
1
@GauravSehgal 相关,但不是重复问题。虽然有相同的根本原因,但问题和目标却截然不同。 - sehe
值得一提的是,std::array<bool>没有这种优化,因此它的行为不同("[...]该容器是一个聚合类型,其语义与持有C风格数组T[N]作为其唯一非静态数据成员的结构相同。"[...])。但是,您失去了调整大小的能力。例如:http://coliru.stacked-crooked.com/a/acc6abad754046cc。 - user1810087
1
改述Scott Meyers的话,“vector<bool>有两个问题。它不是一个向量,也不能存储布尔值”。 - Happy Green Kid Naps
1个回答

18

std::vector<bool>operator[]返回的reference并不是像std::vector的基本特化那样一个bool&的别名。相反,它被C++标准指定为这样

// bit reference:
class reference {
  friend class vector;
  reference() noexcept;
public:
  ~reference();
  operator bool() const noexcept;
  reference& operator=(const bool x) noexcept;
  reference& operator=(const reference& x) noexcept;
  void flip() noexcept;     // flips the bit
};

正如您所看到的,没有声明operator |=。因此,您不能将其应用于从vec_bool [0]返回的引用。

vec_bool[0] = vec_bool[0] | vec_bool[1]; 可行的原因是有一些重载函数可以实现它。 operator bool() 将内置|的两个操作数转换为bool值。然后,reference的赋值运算符将结果分配回vec_bool [0]

根据C++标准的规定,std::vector<bool> 不是一个特别好的抽象,依我之见。


谢谢!您能否告诉我 vector<bool> 是否是唯一的一个与标准实现不同的 vector 类型? - Mees de Vries
6
这个句子的意思是,“这是C++标准指定要与主声明不同的唯一一个,其他所有模板都可以假定为主模板。” 我会优化翻译使其更通俗易懂,但不会改变原来的含义。 - StoryTeller - Unslander Monica
3
换句话说,其他代码可能基于性能原因进行了专门优化,但在可移植的代码中无法检测到这一点。 - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接