【问题标题】:Could std::vector<bool>::iterator implement its deref operator to return a reference to _Bit_reference?std::vector<bool>::iterator 能否实现其 deref 运算符以返回对 _Bit_reference 的引用?
【发布时间】:2021-05-28 16:03:00
【问题描述】:

range-based-for 中循环 std::vector&lt;bool&gt; 以更改数据,需要使用 转发引用 或仅使用 值类型

std::vector<bool> bv(5);
bool val = true;
for(auto&& b : bv) {
    b = val;
    val = !val;
}

或者:

std::vector<bool> bv(5);
bool val = true;
for(auto b : bv) {
    b = val; // yes, this alters the vector
    val = !val;
}

但这不起作用:

std::vector<bool> bv(5);
bool val = true;
for(auto& b : bv) {
  // ...
}

上面的结果与已知的编译错误:

cannot bind non-const lvalue reference of type 'std::_Bit_reference&'
to an rvalue of type 'std::_Bit_iterator::reference'
  9  |     for(auto& b : bv) {
     |                   ^~

问题是,理论上和实践上,std::vector&lt;bool&gt; 是否可以为其迭代器实现 operator*,以返回 引用Bit_reference? p>

在实现一个简单的 BoolArray 版本并且能够循环引用我的内部 BoolProxy 时,我想到了这个问题:

template<size_t SIZE>
class BoolArray {
public:
    // forward declaration
    class iterator;

private:
    char arr[(SIZE-1)/8 + 1] = {};

    class BoolProxy {
        char* const arr;
        size_t index;
        size_t byte_index() const {
            return index / 8;
        }
        size_t bit_index() const {
            return index % 8;
        }
        char bit_val() const {
            return 1 << bit_index();
        }
    public:
        friend class BoolArray<SIZE>::iterator;
        BoolProxy(char* const arr, size_t index): arr(arr), index(index) {} 
        operator bool() const {
            return arr[byte_index()] & bit_val();            
        }
        bool operator=(bool value) {
            if(value) {
                arr[byte_index()] |= bit_val();
            }
            else {
                arr[byte_index()] &= ~(bit_val());
            }
            return value;
        }
    };
public:
    class iterator {
        BoolProxy bp;
    public:
        iterator(BoolProxy bp): bp(bp) {}
        iterator& operator++() {
            ++bp.index;
            return *this;
        }
        bool operator*() const {
            return bp;
        }
        // we return here a BoolProxy byref!
        // is there something wrong with it?
        auto& operator*() {
            return bp;
        }
        bool operator!=(iterator other) {
            return bp.arr != other.bp.arr || bp.index != other.bp.index;
        }
    };
    auto begin() {
        return iterator{BoolProxy{arr, 0}};
    }
    auto end() {
        return iterator{BoolProxy{arr, SIZE}};
    }
};

int main() {
    BoolArray<5> barr;
    bool val = true;
    for(auto& b : barr) { // looping on a reference here
        b = val;
        val = !val;
    }
    for(auto b : barr) {
        std::cout << b << ' ';
    }
}

迭代器确实作为右值返回,但在基于范围的范围内,它的生命周期将被延长,这应该允许从中获取对其内部 BoolProxy 的引用。

代码:https://godbolt.org/z/8xjs16dKG

【问题讨论】:

标签: c++ vector


【解决方案1】:

vector&lt;bool&gt; 不包含Bit_reference 或任何其他此类类型。并且vector&lt;bool&gt; 必须是多通道范围。这意味着无论operator* 返回什么,它都不能是对存储在迭代器中的内容的引用,因为您可以递增迭代器并仍然访问reference 返回的迭代器的先前值:

auto &&ref = *it;
++it;
//`ref` still references the previous bit.

这是您提议的代码失败的地方。

所以如果operator* 是要返回一个对象的引用... 定义 的对象在哪里?它不能在vector&lt;bool&gt; 中,也不能在迭代器中。并且它不能在operator* 中定义,因为那样你会返回一个对本地的引用,一旦函数返回就会被销毁。

那么它在哪里?

它必须是一个临时的,在operator* 自身内创建并按值返回的对象。

【讨论】:

    猜你喜欢
    • 2021-08-16
    • 1970-01-01
    • 2022-11-21
    • 2016-11-12
    • 1970-01-01
    • 2015-08-03
    • 2012-01-14
    相关资源
    最近更新 更多