56 Stimmen

Warum wurde der Paarbereichszugriff aus C++11 entfernt?

Ich habe gerade entdeckt, dass der C++11-Entwurf an einer Stelle std::begin / std::end Überlastungen für std::pair die es erlaubte, ein Paar von Iteratoren als einen Bereich zu behandeln, der für die Verwendung in einer bereichsbasierten for-Schleife geeignet ist (N3126, Abschnitt 20.3.5.5), aber dies wurde inzwischen entfernt.

Weiß jemand, warum sie entfernt wurde?

Ich finde die Entfernung sehr bedauerlich, denn es scheint keine andere Möglichkeit zu geben, ein Paar von Iteratoren als einen Bereich zu behandeln. In der Tat:

  • Die Suchregeln für Anfang/Ende in einer bereichsbasierten for-Schleife besagen, dass Anfang/Ende 1) als Mitgliedsfunktionen des Bereichsobjekts und 2) als freie Funktionen in "verbundenen Namensräumen" gesucht werden.
  • std::pair hat keine Beginn/Ende-Mitgliedsfunktionen
  • Der einzige zugehörige Namespace für std::pair<T, U> ist im Allgemeinen der Namespace std
  • Wir dürfen nicht überlasten std::begin / std::end für std::pair uns selbst
  • Wir können uns nicht spezialisieren std::begin / std::end für std::pair (weil die Spezialisierung partiell sein müsste und das ist bei Funktionen nicht erlaubt)

Gibt es eine andere Möglichkeit, die ich übersehen habe?

44voto

sellibitze Punkte 26706

Ich denke, das Papier von 2009 "Paare ergeben keine guten Reihen" von Alisdair Meredith ist zumindest ein Teil der Antwort. Grundsätzlich geben viele Algorithmen Paare von Iteratoren zurück, bei denen nicht garantiert ist, dass sie gültige Bereiche sind. Es scheint, dass sie die Unterstützung für pair<iterator,iterator> aus diesem Grund aus der for-range-Schleife. Die vorgeschlagene Lösung wurde jedoch nicht vollständig übernommen.

Wenn Sie sicher sind, dass ein Paar von Iteratoren wirklich eine gültige Spanne dann könnten Sie sie in einen benutzerdefinierten Typ einpacken, der begin()/end()-Memberfunktionen bietet:

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))) {
       ...
    }
}

(ungetestet)

Ich stimme zu, dass dies ein bisschen eine Warze ist. Funktionen, die gültige Bereiche zurückgeben (wie equal_range), sollten dies mit einem geeigneten Rückgabetyp angeben. Es ist ein bisschen peinlich, dass wir dies manuell bestätigen müssen durch etwas wie as_range oben.

9voto

mgsergio Punkte 91

Sie können verwenden boost::make_iterator_range . Es konstruiert einen Iterator_range mit begin() y end() Methoden. boost::make_iterator_range kann akzeptieren std::pair von Iteratoren.

6voto

Richard Hodges Punkte 66076

Erweiterung der obigen Antwort unter Verwendung von C++11-Optimierungen:

#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;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X