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

Why was pair range access removed from C++11?

本文关键字:范围 访问 删除 C++11 为什么      更新时间:2023-10-16

我刚刚发现,在某一点上,C++11草案对std::pairstd::begin/std::end重载,这允许将一对迭代器视为适合在基于范围的for循环中使用的范围(N3126,第20.3.5.5节),但这一点后来被删除了。

有人知道它为什么被移走吗?

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

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

我还有别的失踪的原因吗?

我认为Alisdair Meredith在2009年发表的论文《配对不会形成好的范围》至少是答案的一部分。基本上,许多算法返回的迭代器对实际上不能保证是有效的范围。出于这个原因,他们似乎从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之类的东西手动确认这一点,这有点令人尴尬。

您可以使用boost::make_iterator_range。它使用begin()end()方法构造了一个迭代器范围。CCD_ 17可以接受迭代器的CCD_。

使用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 << " timesn"
    << "the sum is " << sum << "n";
return 0;
}