为啥析取赋值运算符 |= 不适用于布尔向量?

Posted

技术标签:

【中文标题】为啥析取赋值运算符 |= 不适用于布尔向量?【英文标题】:Why does the disjunction assignment operator |= not work with vectors of bools?为什么析取赋值运算符 |= 不适用于布尔向量? 【发布时间】:2018-03-14 11:29:21 【问题描述】:

如果我有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|=’(操作数类型是 ‘std::vector::reference aka std::_Bit_reference’ 和 ‘bool’)

【问题讨论】:

你必须记住std::vector&lt;bool&gt;不是一个普通向量。它不是bool 的实际向量,而更像是位向量,C++ 规范未指定其实现。 Why does std::vector<bool> has no .data()?的可能重复 您可以查看en.cppreference.com/w/cpp/container/vector_bool了解更多信息 @GauravSehgal 相关,但不重复。相同的根本原因,但非常不同的问题/目标。 套用 Scott Meyers vector&lt;bool&gt; 有两个问题。它不是向量。它不存储 bools” 【参考方案1】:

std::vector&lt;bool&gt;operator[] 返回的reference 不是bool&amp; 的别名,因为它是std::vector 的主要特化。它由C++ standard as this 指定:

// 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&lt;bool&gt; 并不是一个特别好的抽象,IMO。

【讨论】:

谢谢!您能否告诉我vector&lt;bool&gt; 是否是唯一偏离向量类型的“标准”实现的向量类型? @MeesdeVries - 这是 C++ 标准要求偏离主要声明的唯一一个。您可以假设的所有其他人都是主要模板。 ...也就是说,其他人可能出于性能原因专门化,但您无法在可移植代码中检测到这一点。

以上是关于为啥析取赋值运算符 |= 不适用于布尔向量?的主要内容,如果未能解决你的问题,请参考以下文章

为啥多变量赋值适用于快速排序算法但不适用于逐行赋值?

布尔逻辑运算符

为啥 ~(true^true) 不正确?布尔运算符(否定)适用于“无符号字符”,但不适用于布尔值? (C++)

Fortran 派生类型:重载赋值运算符不适用于“参数”属性

为啥要避免使用递增赋值运算符 (+=) 创建集合

为啥 Java 没有条件与和条件或运算符的复合赋值版本? (&&=, ||=)