Namensräume
Varianten
Aktionen

std::ranges::to

Von cppreference.com
< cpp‎ | ranges
 
 
Bereichsbibliothek
Range-Adaptoren
 
Definiert in der Header-Datei <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)
Hilfsschablonen
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 Exposition*)
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 Exposition*)
template< class Reference, class C >
constexpr auto /*container-appender*/( C& c );
(7) (nur Exposition*)
template< class R, class T >

concept /*container-compatible-range*/ =
    ranges::input_range<R> &&

    std::convertible_to<ranges::range_reference_t<R>, T>;
(8) (nur Exposition*)

Die Überladungen der Range-Konvertierungsfunktion konstruieren ein neues Nicht-View-Objekt aus einem Quellbereich als erstes Argument, indem sie einen Konstruktor aufrufen, der einen Bereich, einen mit std::from_range_t getaggten Bereichskonstruktor, einen Konstruktor, der ein Iterator-Sentinel-Paar nimmt, oder durch Rückwärts-Einfügen jedes Elements des Quellbereichs in das durch die Argumente konstruierte Objekt aufnimmt.

1) Konstruiert ein Objekt vom Typ C aus den Elementen von r auf folgende Weise
1) Konstruktion eines Nicht-View-Objekts, als ob ein Objekt vom Typ C durch direkte Initialisierung (aber nicht direkte Listeninitialisierung) aus dem Quellbereich std::forward<R>(r) und den restlichen funktionalen Argumenten std::forward<Args>(args)... direkt initialisiert würde, wenn std::constructible_from<C, R, Args...> true ist.
2) Andernfalls Konstruktion eines Nicht-View-Objekts, als ob ein Objekt vom Typ C durch direkte Initialisierung (aber nicht direkte Listeninitialisierung) aus dem zusätzlichen Disambiguierungs-Tag std::from_range, dem Quellbereich std::forward<R>(r) und den restlichen funktionalen Argumenten std::forward<Args>(args)... direkt initialisiert würde, wenn std::constructible_from<C, std::from_range_t, R, Args...> true ist.
3) Andernfalls Konstruktion eines Nicht-View-Objekts, als ob ein Objekt vom Typ C durch direkte Initialisierung (aber nicht direkte Listeninitialisierung) 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 Quellbereich muss ein gemeinsamer Bereich sein), und die restlichen Funktionsargumente std::forward<Args>(args)... direkt initialisiert würde, wenn alle untenstehenden Bedingungen true sind
4) Andernfalls Konstruktion eines Nicht-View-Bereichsobjekts, als ob ein Objekt vom Typ C durch direkte Initialisierung (aber nicht direkte Listeninitialisierung) aus den restlichen Funktionsargumenten std::forward<Args>(args)... direkt initialisiert würde, mit dem folgenden äquivalenten Aufruf 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)

Wenn R sized_range(bis C++26)approximately_sized_range(seit C++26) erfüllt 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 verhindern. Jedes Element von r wird an c angehängt.

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

b) Andernfalls ist der Rückgabeausdruck äquivalent zu

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 Bereichskonstruktionen innerhalb des Bereichs ermöglicht, wenn ranges::input_range<ranges::range_reference_t<C>> true ist.

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

Sei /*input-iterator*/ ein Exposition-Only-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;                      // nicht definiert
    pointer operator->() const;                       // nicht definiert
    /*input-iterator*/& operator++();                 // nicht definiert
    /*input-iterator*/ operator++(int);               // nicht definiert
    bool operator==(const /*input-iterator*/&) const; // nicht definiert

};
(nur Exposition*)

Sei /*DEDUCE-EXPR*/ wie folgt definiert

Der Aufruf ist äquivalent zu to<decltype(/*DEDUCE-EXPR*/)>
    (std::forward<R>(r), std::forward<Args>(args)...)
.
3,4) Gibt einen perfekten Weiterleitungs-Aufruf-Wrapper zurück, der auch ein RangeAdaptorClosureObject ist.
5) Ist true, wenn sie ranges::sized_range erfüllt und reservierbar ist.
6) Ist true, wenn ein Element vom Typ Reference an Container durch einen Member-Funktionsaufruf 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 äquivalent zu einem 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 bei der Konstruktion eines Eingabebereichs R verwendet, dessen Bereichsreferenztyp in T konvertierbar sein muss.

Inhalt

[bearbeiten] Parameter

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

[bearbeiten] Rückgabewert

1,2) Ein konstruiertes Nicht-View-Objekt.
3,4) Ein Bereichsadaptor-Closure-Objekt eines nicht spezifizierten Typs mit folgenden Eigenschaften

ranges::to Rückgabetyp

Member-Objekte

Das zurückgegebene Objekt verhält sich so, 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 Verhalten der Zuweisung des zurückgegebenen Objekts nicht spezifiziert ist und die Namen nur zur Veranschaulichung dienen.

Konstruktoren

Der Rückgabetyp von ranges::to (3,4) verhält sich so, als ob seine Kopier-/Move-Konstruktoren eine Member-für-Member-Kopie/-Bewegung durchführen würden. Es ist CopyConstructible, wenn alle seine Member-Objekte (wie oben spezifiziert) CopyConstructible sind, und ist andernfalls MoveConstructible.

Member-Funktionsoperator ()

Gegeben sei ein Objekt G, das aus einem früheren Aufruf von range::to</* siehe unten */>(args...) erhalten wurde. Wenn ein Glvalue g, das G bezeichnet, in einem Funktionsaufrufausdruck g(r) aufgerufen wird, findet eine Invocatiön des gespeicherten Objekts statt, als ob durch

  • ranges::to</* siehe unten */>(r, std::get<Ns>(g.tup)...), wobei
  • r ein Quellbereichsobjekt ist, das input_range erfüllen muss.
  • Ns ein ganzzahliger Pack 0, 1, ..., (sizeof...(Args) - 1) ist.
  • g ist ein lvalue im Funktionsaufrufausdruck, wenn es ein lvalue im Funktionsaufrufausdruck ist, und andernfalls ein rvalue. Somit kann std::move(g)(r) die gebundenen Argumente in den Aufruf bewegen, während g(r) kopieren würde.
  • Das angegebene Template-Argument ist (3) C oder (4) der abgeleitete Typ einer Klassenvorlage C, die view nicht erfüllen darf.

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

[bearbeiten] Ausnahmen

Wirft nur dann, wenn die Konstruktion eines Nicht-View-Objekts eine Ausnahme auslöst.

[bearbeiten] Anmerkungen

Das Einfügen von Elementen in den Container kann Kopien beinhalten, die weniger effizient als Verschiebungen sein können, da während des Indirektionsaufrufs lvalue-Referenzen erzeugt werden. Benutzer können optional views::as_rvalue verwenden, um den Bereich anzupassen, damit seine Elemente während des Indirektionsaufrufs immer eine rvalue-Referenz erzeugen, was eine Verschiebung impliziert.

Die Klammern sind bei Verwendung der Pipe-Syntax obligatorisch.

auto vec = r | std::ranges::to<std::vector>;   // Error
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

[bearbeiten] 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>
 
#ifndef __cpp_lib_format_ranges
#include <format>
#include <sstream>
 
auto print_aid(const auto& v)
{
    std::ostringstream out;
    out << '[';
    for (int n{}; const auto& e : v)
        out << (n++ ? ", " : "") << e;
    out << ']';
    return out;
}
 
template<typename T>
struct std::formatter<std::vector<T>, char>
{
    template<class ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx)
    {
        return ctx.begin();
    }
 
    template<class FmtContext>
    FmtContext::iterator format(auto const& s, FmtContext& ctx) const
    {
        auto out{print_aid(s)};
        return std::ranges::copy(std::move(out).str(), ctx.out()).out;
    }
};
 
template<typename T>
struct std::formatter<std::list<T>, char>
{
    template<class ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx)
    {
        return ctx.begin();
    }
 
    template<class FmtContext>
    FmtContext::iterator format(auto const& s, FmtContext& ctx) const
    {
        auto out{print_aid(s)};
        return std::ranges::copy(std::move(out).str(), ctx.out()).out;
    }
};
#endif
 
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("{}", vec);
 
    auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
    std::println("{}", 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

[2, 4, 6, 8]
[2, 4, 6]

[bearbeiten] 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
einem Programmfehler, wenn R& kein viewable_range modelliert.
wurde wohlgeformt gemacht
LWG 4016 C++23 Der Container-Einfügungszweig von
ranges::to beinhaltete die Verwendung von Einfügeiteratoren.
ersetzt durch direktes Anhängen
von Elementen an den Container.

[bearbeiten] Referenzen

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