首页 文章

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

提问于
浏览
52

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

有谁知道为什么它被删除了?

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

  • 基于范围的for循环中begin / end的查找规则表示在1)中作为范围对象2)的成员函数查找begin / end作为"associated namespaces"中的自由函数

  • std::pair 没有开始/结束成员函数

  • std::pair<T, U> 的唯一关联命名空间通常是命名空间std

  • 我们不允许自己超载 std::begin / std::endstd::pair

  • 我们无法为 std::pair 专门化 std::begin / std::end (因为专业化必须是部分的,而且不允许使用函数)

还有其他方法让我失踪吗?

3 回答

  • 38

    我认为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 手动确认这一点,这有点令人尴尬 .

  • 6

    你可以使用 boost::make_iterator_range . 它使用 begin()end() 方法构造iterator_range . boost::make_iterator_range 可以接受 std::pair 的迭代器 .

  • 8

    使用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;
    }
    

相关问题