web-dev-qa-db-ja.com

ペア範囲アクセスがC ++ 11から削除されたのはなぜですか?

ある時点で、C++ 11ドラフトにstd::beginstd::end/std::pairオーバーロードがあり、イテレータのペアを範囲での使用に適した範囲として扱うことができることを発見しました- forループ(N3126、セクション20.3.5.5)に基づいていますが、これはその後削除されました。

なぜ削除されたのか誰か知っていますか?

イテレータのペアを範囲として扱う方法は他にないように思われるため、削除は非常に残念です。確かに:

  • 範囲ベースのforループでの開始/終了のルックアップルールでは、開始/終了は1)範囲オブジェクトのメンバー関数として2)「関連付けられた名前空間」のフリー関数として検索されます。
  • std::pairには開始/終了メンバー関数がありません
  • 一般に、std::pair<T, U>に関連付けられている名前空間はnamespacestdのみです。
  • std::beginのためにstd::end/std::pairをオーバーロードすることは許可されていません
  • std::begin/std::endstd::pairに特化することはできません(特殊化は部分的である必要があり、関数では許可されていないため)

私が行方不明になっている他の方法はありますか?

54
HighCommander4

私は2009年の論文 「ペアは良い範囲を作らない」 AlisdairMeredithによると少なくとも答えの一部だと思います。基本的に、多くのアルゴリズムは、実際には有効な範囲であることが保証されていないイテレータのペアを返します。このため、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のような方法でこれを手動で確認する必要があるのは少し恥ずかしいことです。

41
sellibitze

_boost::make_iterator_range_を使用できます。 begin()およびend()メソッドを使用してiterator_rangeを構築します。 _boost::make_iterator_range_は_std::pair_のイテレータを受け入れることができます。

8
mgsergio

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;
}
6
Richard Hodges