fir*_*rda 3 c++ boolean stdvector auto c++11
我发现for (auto& e : cont)有时使用而不是普通for (auto e : cont)(cont例如,某些容器std::vector).到目前为止,我找到了两个原因:
std::thread)经过几次测试,我可以看到:
for (auto& e : cont)适用于任何std::vector<T>除外std::vector<bool>for (cont::reference e : cont)适用于任何std::vector<T> 包括std::vector<bool>(这里显而易见的问题是:for (auto& e : cont)?std::vector<bool>不被认为是真正的容器,许多人认为它应该被重命名(实现很好,很有用,但应该有不同的名称,如bitset或bitfield或dynamic_bitset)std::vector<bool>可以以一种for (auto& e : cont)可行的方式实现(参见下面的尝试)这是我用于测试的代码:(
诀窍是使用reference& iterator::operator * () { return *this; })
#include <vector>
#include <iostream>
#include <typeinfo>
using namespace std;
#define USE_STD_VECT_BOOL 0
#if USE_STD_VECT_BOOL
typedef vector<bool> BITS;
#else
typedef class bvect {
unsigned data; // we could use vector<unsigned> but this is just an examle
unsigned size;
public:
bvect(): data(0), size(0) {}
void push_back(bool value) {
if(value) data |= (1u<<size);
size++; }
class reference {
friend class bvect;
protected:
unsigned& data;
unsigned flag;
reference(unsigned& data, unsigned flag)
: data(data), flag(flag) {}
public:
operator bool() const {
return data & flag; }
reference& operator = (bool value) {
if(value) data |= flag;
else data &= ~flag;
return *this; }
};
class iterator: protected reference {
friend class bvect;
iterator(unsigned& data, unsigned flag)
: reference(data, flag) {}
public:
typedef bool value_type;
typedef bvect::reference reference;
typedef input_iterator_tag iterator_category;
// HERE IS THE TRICK:
reference& operator * () {
return *this; }
iterator& operator ++ () {
flag <<= 1;
return *this; }
iterator operator ++ (int) {
iterator tmp(*this);
operator ++ ();
return tmp; }
bool operator == (const iterator& rhs) {
return flag == rhs.flag; }
bool operator != (const iterator& rhs) {
return flag != rhs.flag; }
};
iterator begin() {
return iterator(data, 1); }
iterator end() {
return iterator(data, 1<<size); }
} BITS;
#endif
int main() {
BITS bits;
bits.push_back(0);
bits.push_back(1);
#if !USE_STD_VECT_BOOL
// won't compile for vector<bool>
for(auto& a : bits)
cout << typeid(a).name()
<< " = " << (int)(bool)a
<< endl;
#endif
// std::_Bit_Reference
for(BITS::reference a : bits)
cout << typeid(a).name()
<< " = " << (int)(bool)a
<< endl;
// few more tests
for(auto a : bits)
cout << (int)(bool)a;
for(bool a : bits)
cout << (int)(bool)a;
cout << endl;
}
Run Code Online (Sandbox Code Playgroud)
问题:
for (cont::reference e : cont)而不是for (auto& e : cont)?bvect::reference& bvect::iterator::operator * () { return *this; }这里提到.vector<bool>)反馈:答案和评论:
for (auto&& e : cont)(用于写入)或for (const auto& e : cont)(用于读取/枚举)似乎在所有情况下都有效.(感谢dyp和Praetorian)typename iterator_traits<decltype(begin(cont))>::reference似乎甚至可以用于数组(cont = boo [2]).(是的,它很难看但可以使用我认为的一些模板别名来缩短.我想不到反例这里需要它,所以,现在,这不是解决方案.auto&&是)iterator::operator * ()必须返回iterator::reference(不iterator::reference&),但仍然不知道为什么.最终裁决:
auto it = bits.begin();
auto&& e = *it; cout << (bool)e;
it++; cout << (bool)e;
cout << endl;
Run Code Online (Sandbox Code Playgroud)
输出:
10
Run Code Online (Sandbox Code Playgroud)
这绝对是坏事.我们应该坚持标准(iterator::operator * ()必须返回iterator::reference).谢谢 :)
vector<bool>是vector类模板的特化,它将布尔值存储在位域中以进行空间优化.由于您无法返回对位域的引用,因此vector<bool>::reference是类类型,代表单个的代理bool.vector<bool>::operator[]按值返回此代理类实例; 这同样适用于解除引用a vector<bool>::iterator.
vector<bool> cont;
for (auto& e : cont) { ... }
Run Code Online (Sandbox Code Playgroud)
在这里,您尝试将左值引用绑定到右值,这是不允许的.
我应该使用
for (cont::reference e : cont)而不是for (auto& e : cont)?
诀窍有什么问题?任何用例都可以增强它吗?
基于范围的优点是它适用于普通的C数组.cont::reference对于那些,以及没有名为成员类型的任何可迭代类型,使用将失败reference.for(auto const& e : cont)如果您希望只读取循环中的容器元素,并且for(auto&& e : cont)想要修改元素,则应该使用.
在后一种情况下,auto&& e是一个可以绑定到左值和右值的通用引用,所以它也适用于这种vector<bool>情况.
| 归档时间: |
|
| 查看次数: |
1307 次 |
| 最近记录: |