运算符 |= 在 std::vector<bool> 上
Posted
技术标签:
【中文标题】运算符 |= 在 std::vector<bool> 上【英文标题】:operator |= on std::vector<bool> 【发布时间】:2015-03-05 16:35:23 【问题描述】:以下代码无法编译
#include <vector>
int main()
std::vector<bool> enable(10);
enable[0] |= true;
return 0;
给出错误
no match for ‘operator|=’ (operand types are ‘std::vector<bool>::reference aka std::_Bit_reference’ and ‘bool’)
在我的实际代码中,我有一个位字段,其中包含我想要|=
的值以及函数的结果。
有很多简单的方法可以表达相同的想法,但是有什么好的理由不提供这样的运算符吗?
【问题讨论】:
你仍然可以做enable[0] = enable[0] | ...
。
为什么不使用bitset
@Borgleader 在我的真实代码中长度是动态的
@Borgleader:因为那也不直接支持这个操作。
@Amxx,也许是 Boost 的dynamic_bitset
?它的引用类型确实有复合赋值重载。
【参考方案1】:
主要原因是std::vector<bool>
是特殊的,它的规范特别允许实现以最小化内存使用。
对于bool
以外的任何向量,引用类型实际上可以是真正的引用(即std::vector<int>::reference
实际上可以是int &
) - 通常直接引用向量本身的元素。因此,引用类型支持底层类型可以进行的所有操作是有意义的。这是因为vector<int>
在内部有效地管理int
的连续数组。除了bool
之外的所有类型也是如此。
但是,为了最大限度地减少内存使用,std::vector<bool>
可能无法(实际上可能不会)在内部与bool
的实际数组一起使用。相反,它可能会使用一些打包的数据结构,例如内部的unsigned char
数组,其中每个unsigned char
是一个包含8
位的位域。因此,长度为 800 的 vector<bool>
实际上会管理 100
unsigned char 的数组,并且它消耗的内存将是 100
字节(假设没有过度分配)。如果vector<bool>
实际上包含800
bool
的数组,则其内存使用量至少为800
字节(因为根据定义,sizeof(bool) 必须至少为1
)。
为了允许vector<bool>
的实现者进行这种内存优化,vector<bool>::operator[]
的返回类型(即std::vector<bool>::reference
)不能简单地是bool &
。在内部,它可能包含对底层类型的引用(例如unsigned char
)和跟踪它实际影响的位的信息。这将使所有 op=
运算符(+=
、-=
、|=
等)对底层类型进行一些昂贵的操作(例如位摆弄)。
std::vector<bool>
的设计者将面临选择
指定std::vector<bool>::reference
支持所有
op=
并不断听到来自
使用这些运算符的程序员
不要支持那些 op=
和那些认为这样的事情没问题(“更简洁的代码”等)的程序员的抱怨,即使它们效率低下。
看来std::vector<bool>
的设计者选择了选项2。结果是std::vector<bool>::reference
支持的唯一赋值运算符是标准operator=()
(操作数类型为reference
,或类型为@ 987654358@) 不是任何 op=
。这种选择的好处是,如果程序员试图做一些在实践中实际上是一个糟糕的选择,就会得到一个编译错误。
毕竟,尽管bool
支持所有 op=
,但使用它们并没有太大的作用。例如,some_bool |= true
与some_bool = true
具有相同的净效应。
【讨论】:
【参考方案2】:你为什么不做以下事情?
enable[0] = enable[0] | true;
【讨论】:
这就是我正在做的事情,但仍然会发现 |= 运算符更清洁......(不是我喜欢那种运算符,例如使用^= true
切换布尔值)
您可以按照 David Schwartz 的建议重载运算符,但我认为对于这样一个基本操作,这已经足够了。您的来电。
我也不认为值得添加一个运算符(特别是如果它写得不好并且包含分支)。然而对我来说,像|=
这样的操作员的主要观点是不必使用变量,从而降低了提示的风险
如果你坚持要引入新的算子,大卫施瓦茨的答案就是解决你的问题。
@erip: enable[0]
在逻辑上表示单个真/假值。 (它实际上是复杂的等等等等,但它代表单个真/假值)【参考方案3】:
你应该可以很容易地自己制作一个。比如:
std::vector<bool>::reference& operator |= (std::vector<bool>::reference& a, bool b)
if (b)
a = true;
return a;
或者,std::bitset 很合适。
【讨论】:
【参考方案4】:简短而甜蜜的回答:应该避免std::vector<bool>
。请改用vector<wchar>
。你实际上得到了一个容器,其中 bool 被打包成位,它给出了与其他向量不同的行为、慢代码并且无论如何没人关心内存。我想现在已经没有人喜欢这个了,但是倒转时钟会破坏太多代码......
【讨论】:
以上是关于运算符 |= 在 std::vector<bool> 上的主要内容,如果未能解决你的问题,请参考以下文章
将 std::vector 分配给 std::valarray