Namespaces
Variants

std::ranges::to

Von de.cppreference.net
 
 
Ranges-Bibliothek
Range-Adapter
 
Definiert in Header <ranges>
template< class C, ranges::input_range R, class... Args >
    requires (!ranges::view<C>)
constexpr C to( R&& r, Args&&... args );
(1) (seit C++23)
template< template< class... > class C,
          ranges::input_range R, class... Args >
constexpr auto to( R&& r, Args&&... args );
(2) (seit C++23)
template< class C, class... Args >
    requires (!ranges::view<C>)
constexpr /*range adaptor closure*/ to( Args&&... args );
(3) (seit C++23)
template< template< class... > class C, class... Args >
constexpr /*range adaptor closure*/ to( Args&&... args );
(4) (seit C++23)
Hilfsvorlagen
template< class Container >
constexpr bool /*reservable-container*/ =
    ranges::sized_range<Container> &&
    requires (Container& c, ranges::range_size_t<Container> n)
    {
        c.reserve(n);
        { c.capacity() } -> std::same_as<decltype(n)>;
        { c.max_size() } -> std::same_as<decltype(n)>;
    };
(5) (nur zur Darstellung*)
template< class Container, class Reference >
constexpr bool /*container-appendable*/ =
    requires (Container& c, Reference&& ref)
    {
        requires
        (
            requires { c.emplace_back(std::forward<Reference>(ref)); }     ||
            requires { c.push_back(std::forward<Reference>(ref)); }        ||
            requires { c.emplace(c.end(), std::forward<Reference>(ref)); } ||
            requires { c.insert(c.end(), std::forward<Reference>(ref)); }
        );
    };
(6) (nur zur Darstellung*)
template< class Reference, class C >
constexpr auto /*container-appender*/( C& c );
(7) (nur zur Darstellung*)
template< class R, class T >
concept /*container-compatible-range*/ =
    ranges::input_range<R> &&
    std::convertible_to<ranges::range_reference_t<R>, T>;
(8) (nur zur Darstellung*)

Die Überladungen der Range-Konvertierungsfunktion konstruieren ein neues Nicht-View-Objekt aus einem Quell-Range als erstes Argument, indem sie einen Konstruktor aufrufen, der einen Range, einen mit std::from_range_t getaggten Range-Konstruktor, einen Konstruktor, der ein Iterator-Sentinel-Paar akzeptiert, oder indem sie jedes Element des Quell-Ranges per Back-Insertion in das aus den Argumenten konstruierte Objekt einfügt.

1) Konstruiert ein Objekt vom Typ C aus den Elementen von r wie folgt:
a) Falls C nicht input_range erfüllt oder std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> ist true:
1) Konstruktion eines Nicht-View-Objekts, als ob direkt-initialisiert (aber nicht direkt-Listen-initialisiert) würde, ein Objekt vom Typ C aus dem Quell-Range std::forward<R>(r) und den restlichen Funktionsargumenten std::forward<Args>(args)..., falls std::constructible_from<C, R, Args...> ist true.
2) Andernfalls Konstruktion eines Nicht-View-Objekts, als ob direkt-initialisiert (aber nicht direkt-Listen-initialisiert) würde, ein Objekt vom Typ C aus dem zusätzlichen Disambiguierungs-Tag std::from_range, dem Quell-Range std::forward<R>(r) und den restlichen Funktionsargumenten std::forward<Args>(args)..., falls std::constructible_from<C, std::from_range_t, R, Args...> ist true.
3) Andernfalls Konstruktion eines Nicht-View-Objekts, als ob direkt-initialisiert (aber nicht direkt-Listen-initialisiert) würde, ein Objekt vom Typ C aus dem Iterator-Sentinel-Paar (ranges::begin(r) als Iterator und ranges::end(r) als Sentinel, wobei Iterator und Sentinel denselben Typ haben. Mit anderen Worten, der Quell-Range muss ein common_range sein), und den restlichen Funktionsargumenten std::forward<Args>(args)..., falls alle der folgenden Bedingungen true sind:
  • ranges::common_range<R>
  • Falls std::iterator_traits<ranges::iterator_t<R>>::iterator_category gültig ist und einen Typ bezeichnet, der std::derived_from<std::input_iterator_tag>
  • std::constructible_from<C, ranges::iterator_t<R>, ranges::sentinel_t<R>, Args...>
erfüllt4) Andernfalls Konstruktion eines Nicht-View-Range-Objekts, als ob direkt-initialisiert (aber nicht direkt-Listen-initialisiert) würde, ein Objekt vom Typ C aus den restlichen Funktionsargumenten std::forward<Args>(args)... mit dem folgenden äquivalenten Aufruf unten nach der Konstruktion:

if constexpr (ranges::sized_range<R> && /*reservable-container*/<C>)
    c.reserve(static_cast<ranges::range_size_t<C>>(ranges::size(r)));
ranges::for_each(r, /*container-appender*/(c));

(bis C++26)

if constexpr (ranges::approximately_sized_range<R>
            && /*reservable-container*/<C>)
    c.reserve(static_cast<ranges::range_size_t<C>>(ranges::reserve_hint(r)));
ranges::for_each(r, /*container-appender*/(c));

(seit C++26)

Falls das R sized_range(bis C++26)approximately_sized_range(seit C++26) und C reservable-container erfüllt, kann das konstruierte Objekt c vom Typ C Speicher mit der anfänglichen Speichergröße ranges::size(r)(bis C++26)ranges::reserve_hint(r)(seit C++26) reservieren, um zusätzliche Allokationen während des Einfügens neuer Elemente zu vermeiden. Jedes Element von r wird an c angehängt.

Die obigen Operationen sind gültig, falls beide der folgenden Bedingungen true sind:

b) Andernfalls entspricht der Rückgabeausdruck
to<C>(ranges::ref_view(r) | views::transform([](auto&& elem)
{
    return to<ranges::range_value_t<C>>(std::forward<decltype(elem)>(elem));
}), std::forward<Args>(args)...)

Was verschachtelte Range-Konstruktionen innerhalb des Ranges erlaubt, falls ranges::input_range<ranges::range_reference_t<C>> ist true.

Andernfalls ist das Programm fehlerhaft.
2) Konstruiert ein Objekt des abgeleiteten Typs aus den Elementen von r.

Sei /*input-iterator*/ ein Nur-zur-Darstellung-Typ, der LegacyInputIterator erfüllt:

struct /*input-iterator*/
{
    using iterator_category = std::input_iterator_tag;
    using value_type = ranges::range_value_t<R>;
    using difference_type = std::ptrdiff_t;
    using pointer = std::add_pointer_t<ranges::range_reference_t<R>>;
    using reference = ranges::range_reference_t<R>;
    reference operator*() const;                      // not defined
    pointer operator->() const;                       // not defined
    /*input-iterator*/& operator++();                 // not defined
    /*input-iterator*/ operator++(int);               // not defined
    bool operator==(const /*input-iterator*/&) const; // not defined
};
(nur zur Darstellung*)

Sei /*DEDUCE-EXPR*/ wie folgt definiert:

  • C(std::declval<R>(), std::declval<Args>()...), falls dieser Ausdruck gültig ist.
  • Andernfalls,
C(std::from_range, std::declval<R>(),
  std::declval<Args>()...)
, falls dieser Ausdruck gültig ist.
  • Andernfalls,
C(std::declval</*input-iterator*/>(),
  std::declval</*input-iterator*/>(),
  std::declval<Args>()...)
, falls dieser Ausdruck gültig ist.
  • Andernfalls ist das Programm fehlerhaft.

Der Aufruf ist äquivalent zu

to<decltype(/*DEDUCE-EXPR*/)>
  (std::forward<R>(r), std::forward<Args>(args)...)
.
3,4) Gibt einen perfekten Weiterleitungs-Call-Wrapper zurück, der auch ein RangeAdapterAbschlussobjekt ist.
5) Ist true, falls es ranges::sized_range erfüllt und berechtigt ist, reservierbar zu sein.
6) Ist true, falls ein Element vom Typ Reference an Container durch einen Memberfunktionsaufruf emplace_back, push_back, emplace oder insert angehängt werden kann.
7) Gibt ein Funktionsobjekt zurück, bei dem ein Aufruf des zurückgegebenen Funktionsobjekts ausdrucksäquivalent zum Anhängen eines Elements an einen Container ist. Der Rückgabeausdruck ist äquivalent zu
return [&c]<class Reference>(Reference&& ref)
{
    if constexpr (requires { c.emplace_back(std::declval<Reference>()); })
        c.emplace_back(std::forward<Reference>(ref));
    else if constexpr (requires { c.push_back(std::declval<Reference>()); })
        c.push_back(std::forward<Reference>(ref));
    else if constexpr (requires { c.emplace(c.end(),
                                            std::declval<Reference>()); })
        c.emplace(c.end(), std::forward<Reference>(ref));
    else
        c.insert(c.end(), std::forward<Reference>(ref));
};
8) Wird in der Definition von Containern beim Konstruieren eines Eingabe-Ranges R verwendet, dessen Range-Referenztyp in T konvertierbar sein muss.

Parameter

r - ein Quellbereichsobjekt
args - Liste der Argumente zum ( 1,2 ) Konstruieren eines Bereichs oder ( 3,4 ) Binden an die letzten Parameter eines Range-Adapter-Closure-Objekts
Typanforderungen
-
C muss ein cv-unqualifizierter Klassentyp sein ( 1,3 )

Rückgabewert

1,2) Ein konstruiertes Nicht-Ansichtsobjekt.
3,4) Ein Range-Adaptor-Closure-Objekt nicht spezifizierten Typs mit folgenden Eigenschaften:

ranges::to Rückgabetyp

Member-Objekte

Das zurückgegebene Objekt verhält sich, als hätte es kein Zielobjekt, und ein std::tuple Objekt tup konstruiert mit std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) , außer dass das Zuweisungsverhalten des zurückgegebenen Objekts nicht spezifiziert ist und die Namen nur zur Darstellung dienen.

Konstruktoren

Der Rückgabetyp von ranges::to ( 3,4 ) verhält sich, als ob seine Kopier-/Verschiebekonstruktoren eine elementweise Kopie/Verschiebung durchführen. Er ist CopyConstructible , wenn alle seine Member-Objekte (oben spezifiziert) CopyConstructible sind, andernfalls ist er MoveConstructible .

Member-Funktion operator()

Gegeben ein Objekt G , erhalten von einem früheren Aufruf von range :: to < /* see below */ > ( args... ) , wenn ein Glvalue g , das G bezeichnet, in einem Funktionsaufrufausdruck g ( r ) aufgerufen wird, findet ein Aufruf des gespeicherten Objekts statt, als ob durch

  • ranges :: to < /* see below */ > ( r, std :: get < Ns > ( g. tup ) ... ) , wobei
  • r ist ein Quell-Range-Objekt, das input_range erfüllen muss.
  • Ns ist ein Integer-Pack 0 , 1 , ..., ( sizeof... ( Args ) - 1 ) .
  • g ist ein Lvalue im Aufrufausdruck, wenn es ein Lvalue im Aufrufausdruck ist, andernfalls ist es ein Rvalue. Daher kann std :: move ( g ) ( r ) die gebundenen Argumente in den Aufruf verschieben, während g ( r ) kopieren würde.
  • Das spezifizierte Template-Argument ist ( 3 ) C oder ( 4 ) der abgeleitete Typ von einem Klassentemplate C , das nicht view erfüllen darf.

Das Programm ist fehlerhaft, wenn g einen volatile-qualifizierten Typ hat.

Ausnahmen

Wirft nur, wenn die Konstruktion eines Non-View-Objekts eine Ausnahme wirft.

Hinweise

Das Einfügen von Elementen in den Container kann Kopiervorgänge beinhalten, die weniger effizient sein können als Verschiebeoperationen, da bei dem Indirektionsaufruf Lvalue-Referenzen erzeugt werden. Benutzer können optional views:: as_rvalue verwenden, um den Bereich so anzupassen, dass dessen Elemente bei dem Indirektionsaufruf stets eine Rvalue-Referenz erzeugen, was eine Verschiebeoperation impliziert.

Die Klammern sind obligatorisch bei Verwendung der Pipe-Syntax.

auto vec = r | std::ranges::to<std::vector>;   // Fehler
auto vec = r | std::ranges::to<std::vector>(); // OK
Feature-Test Makro Wert Std Feature
__cpp_lib_ranges_to_container 202202L (C++23) std::ranges::to
__cpp_lib_ranges_reserve_hint 202502L (C++26) ranges::approximately_sized_range , ranges::reserve_hint , und Änderungen an std::ranges::to

Beispiel

Ein Vorschaulink: Compiler Explorer

#include <boost/container/devector.hpp>
#include <concepts>
#include <initializer_list>
#include <list>
#include <print>
#include <ranges>
#include <regex>
#include <string>
#include <vector>

int main()
{
    auto vec = std::views::iota(1, 5)
             | std::views::transform([](int v){ return v * 2; })
             | std::ranges::to<std::vector>();

    static_assert(std::same_as<decltype(vec), std::vector<int>>);
    std::println("1) {}", vec);

    auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
    std::println("2) {}", list);
}

void ctor_demos()
{
    // 1.a.1) Direct init
    {
        char array[]{'a', 'b', '\0', 'c'};

        // Argument type is convertible to result value type:
        auto str_to = std::ranges::to<std::string>(array);
        // Equivalent to
        std::string str(array);

        // Result type is not an input range:
        auto re_to = std::ranges::to<std::regex>(array);
        // Equivalent to
        std::regex re(array);
    }

    // 1.a.2) from_range ctor
    {
        auto list = {'a', 'b', '\0', 'c'};

        // Argument type is convertible to result value type:
        auto str_to = std::ranges::to<std::string>(list);
        // Equivalent to
        // std::string str(std::from_range, list);

        // Result type is not an input range:
        [[maybe_unused]]
        auto pair_to = std::ranges::to<std::pair<std::from_range_t, bool>>(true);
        // Equivalent to
        std::pair<std::from_range_t, bool> pair(std::from_range, true);
    }

    // 1.a.3) iterator pair ctor
    {
        auto list = {'a', 'b', '\0', 'c'};

        // Argument type is convertible to result value type:
        auto devector_to = std::ranges::to<boost::container::devector<char>>(list);
        // Equivalent to
        boost::container::devector<char> devector(std::ranges::begin(list),
                                                  std::ranges::end(list));

        // Result type is not an input range:
        std::regex re;
        auto it_to = std::ranges::to<std::cregex_iterator>(list, re);
        // Equivalent to
        std::cregex_iterator it(std::ranges::begin(list), std::ranges::end(list), re);
    }
}

Ausgabe:

1) [2, 4, 6, 8]
2) [2, 4, 6]

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
LWG 3984 C++23 der verschachtelte Konstruktionszweig von ranges::to führte zu
Programm ill-formed wenn R& kein viewable_range modelliert
als well-formed festgelegt
LWG 4016 C++23 der Container-Einfügezweig von
ranges::to beinhaltete Verwendung von Insert-Iteratoren
ersetzt durch direktes Anhängen
von Elementen an Container

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 26.5.7 Bereichskonvertierungen [range.utility.conv]