为什么从C ++ 11中删除了对范围访问?

时间:2011-05-29 11:55:48

标签: c++ foreach c++11 range std-pair

我刚刚发现,在某一时刻,C ++ 11草案对std::begin的{​​{1}} / std::end重载允许将一对迭代器视为适合在基于范围的for循环(N3126,第20.3.5.5节),但此后已被删除。

有谁知道它被删除的原因?

我发现删除非常不幸,因为似乎没有其他方法可以将一对迭代器视为范围。事实上:

  • 基于范围的for循环中begin / end的查找规则表示在1)中作为范围对象2)的成员函数查找begin / end作为“关联命名空间”中的自由函数
  • std::pair没有开始/结束成员函数
  • std::pair唯一关联的命名空间通常是namespace std
  • 我们不允许std::pair<T, U> / std::beginstd::end自己重载
  • 我们无法为std::pair专门化std::begin / std::end(因为专业化必须是部分的,而且不允许使用函数)

我还有其他方法吗?

2 个答案:

答案 0 :(得分:40)

我认为Alisdair Meredith撰写的2009年论文"Pairs do not make good ranges"至少是答案的一部分。基本上,许多算法返回的迭代器对实际上并不保证是有效范围。由于这个原因,他们似乎从for-range循环中删除了对pair<iterator,iterator>的支持。但是,提出的解决方案尚未完全采用。

如果您确定某些迭代器实际上代表有效范围,那么您可以将它们包装成提供begin()/ end()成员函数的自定义类型:

template<class Iter>
struct iter_pair_range : std::pair<Iter,Iter> {
    iter_pair_range(std::pair<Iter,Iter> const& x)
    : std::pair<Iter,Iter>(x)
    {}
    Iter begin() const {return this->first;}
    Iter end()   const {return this->second;}
};

template<class Iter>
inline iter_pair_range<Iter> as_range(std::pair<Iter,Iter> const& x)
{ return iter_pair_range<Iter>(x); }

int main() {
    multimap<int,int> mm;
    ...
    for (auto& p : as_range(mm.equal_range(42))) {
       ...
    }
}

(未测试的)

我同意这有点像疣。返回有效范围的函数(如equal_range)应该使用适当的返回类型。我们必须通过上面的as_range手动确认这一点,这有点令人尴尬。

答案 1 :(得分:6)

使用c ++ 11优化扩展上述答案:

#include <utility>

template<class Iter>
struct range_t : public std::pair<Iter, Iter> {
    using pair_t = std::pair<Iter, Iter>;
    range_t(pair_t&& src)
    : std::pair<Iter, Iter>(std::forward<pair_t>(src))
    {}

    using std::pair<Iter, Iter>::first;
    using std::pair<Iter, Iter>::second;

    Iter begin() const { return first; }
    Iter end() const { return second; }
};

template<class Iter>
range_t<Iter> range(std::pair<Iter, Iter> p) {
    return range_t<Iter>(std::move(p));
}

template<class Iter>
range_t<Iter> range(Iter i1, Iter i2) {
    return range_t<Iter>(std::make_pair(std::move(i1), std::move(i2)));
}


// TEST: 

#include <iostream>
#include <set>
using namespace std;

int main() {

    multiset<int> mySet { 6,4,5,5,5,3,3,67,8,89,7,5,45,4,3 };

    cout << "similar elements: ";
    for (const auto&i : range(mySet.lower_bound(5), mySet.upper_bound(10))) {
        cout << i << ",";
    }
    cout << "\n";

    int count = 0, sum = 0;
    for (const auto& i: range(mySet.equal_range(5)))
    {
        ++count;
        sum += i;
    }
    cout << "5 appears " << count << " times\n"
    << "the sum is " << sum << "\n";

return 0;
}