std::ranges::to
| Definiert in der Header-Datei <ranges> |
||
template< class C, ranges::input_range R, class... Args > requires (!ranges::view<C>) |
(1) | (seit C++23) |
| template< template< class... > class C, ranges::input_range R, class... Args > |
(2) | (seit C++23) |
template< class C, class... Args > requires (!ranges::view<C>) |
(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*/ = |
(5) | (nur Exposition*) |
template< class Container, class Reference > constexpr bool /*container-appendable*/ = |
(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*/ = |
(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.
C aus den Elementen von r auf folgende WeiseC nicht input_range erfüllt oder std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> true istC 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.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.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- ranges::common_range<R>
- Wenn std::iterator_traits<ranges::iterator_t<R>>::iterator_category gültig ist und einen Typ bezeichnet, der std::derived_from<std::input_iterator_tag> erfüllt
- std::constructible_from<C, ranges::iterator_t<R>, ranges::sentinel_t<R>, Args...>
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>) |
(bis C++26) |
|
if constexpr (ranges::approximately_sized_range<R> |
(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
- std::constructible_from<C, Args...>
-
container-appendable<C, ranges::range_reference_t<R>>
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.
Sei /*input-iterator*/ ein Exposition-Only-Typ, der LegacyInputIterator erfüllt
struct /*input-iterator*/ { |
(nur Exposition*) | |
Sei /*DEDUCE-EXPR*/ wie folgt definiert
- C(std::declval<R>(), std::declval<Args>()...), wenn dieser Ausdruck gültig ist.
- Andernfalls C(std::from_range, std::declval<R>(),
std::declval<Args>()...), wenn dieser Ausdruck gültig ist. - Andernfalls C(std::declval</*input-iterator*/>(),
std::declval</*input-iterator*/>(),
std::declval<Args>()...), wenn dieser Ausdruck gültig ist. - Andernfalls ist das Programm fehlerhaft.
(std::forward<R>(r), std::forward<Args>(args)...).
Reference an Container durch einen Member-Funktionsaufruf emplace_back, push_back, emplace oder insert angehängt werden kann.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));
};
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
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_rangeerfü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)
Coder (4) der abgeleitete Typ einer KlassenvorlageC, dieviewnicht erfüllen darf.
- r ein Quellbereichsobjekt ist, das
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 zueinem Programmfehler, wenn R& kein viewable_range modelliert. |
wurde wohlgeformt gemacht |
| LWG 4016 | C++23 | Der Container-Einfügungszweig vonranges::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]