使用不带const_iterator的boost_foreach

时间:2011-08-13 10:29:40

标签: c++ boost foreach iterator const

有没有办法在不定义const_iterator的情况下使用boost foreach?

我的用例是一个向量的迭代器,它可以包含无效元素。迭代器应遍历向量,并仅生成有效元素。它还应该修复向量,因为它应该将每个无效项与下一个有效项交换,并在结尾处调整向量的大小。例如,如果-1表示无效值,则向量[6,-1,-1,9,-1,2]应迭代超过6,9和2,并将向量保留为[6,9,2]。

我尝试使用boost::iterator_facade实现此功能,但我想不出实现const_iterator的方法,因为矢量可以通过删除无效值来更改,因此不能是const。< / p>

2 个答案:

答案 0 :(得分:1)

关注点分离:容器负责其不变量,遍历的迭代器。如果将修复移动到容器,则可以将逻辑const与隐藏的mutable隐藏部分分开。

你能用“最愚蠢”的方式编写你的迭代器,将它们从容器中解开吗?例如,存储数字索引(如果它对您的容器有意义),然后调用容器的私人朋友(或更多)来访问逻辑第n个元素。

私人朋友可以在const上重载,并且仍然可以修改mutable部分以进行您描述的修复,然后返回该元素。


支持随机访问的容器(以及访问的数字索引)的一个(删节)示例:

template<typename T>
class vector {
    mutable std::vector<std::weak_ptr<T>> data; // notice mutable

    T&
    fetch(int n);

    T const&
    fetch(int n) const; // notice const overload

public:
    class const_iterator;
    friend class const_iterator;

    const_iterator
    begin() const;
};

template<typename T>
class vector<T>::const_iterator {
    int index;
    vector<T> const* this_; // notice const
public:
    // constructors go here

    const_iterator&
    operator++()
    { ++index; }
    // ...

    T const&
    operator*() const
    { return this_->fetch(index); } // this will call the const version of fetch
};

// example implementation of the const version of fetch
template<typename T>
T const&
vector<T>::fetch(int n) const
{
    auto removed = std::remove_if(data.begin(), data.end(), [](std::weak_ptr<T>& element)
    { return element.expired(); });
    // mutate mutable data member in a logically const member
    data.erase(data.begin(), removed);

    // this assumes that there is no race condition
    // bear with me for the sake of understanding the mutable keyword
    return *data[n].lock();
}

答案 1 :(得分:0)

所有形式的“foreach”都专门用于迭代容器的每个元素。您不是只是迭代容器的每个元素。您在迭代时修改容器。

所以只需编写一个常规的for循环。没有必要特别聪明或任何事情。


以下是代码:

std::vector<int> it = vec.begin();
for(; it != vec.end;)
{
  if(*it < 0)
  {
    it = vec.erase(it);
    continue;
  }
  else
  {
    //Do stuff with `it`.
    ++it;
  }
}

看,只是一个简单的循环。不需要花哨的迭代器外墙或其他类似的噱头。