|
Range primitives | |||||||
|
Range concepts | |||||||||||||||||||
|
Range factories | |||||||||
|
Range adaptors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Helper items | |||||||||||||||||
|
Defined in header <ranges> | ||
template<class C,ranges::input_range R,class...Args> requires(!ranges::view<C>) | (1) | (since C++23) |
template<template<class...>class C, ranges::input_range R,class...Args> | (2) | (since C++23) |
template<class C,class...Args> requires(!ranges::view<C>) | (3) | (since C++23) |
template<template<class...>class C,class...Args> constexpr/*range adaptor closure*/ to( Args&&...args); | (4) | (since C++23) |
Helper templates | ||
template<class Container> constexprbool/*reservable-container*/= | (5) | (exposition only*) |
template<class Container,class Reference> constexprbool/*container-appendable*/= | (6) | (exposition only*) |
template<class Reference,class C> constexprauto/*container-appender*/( C& c); | (7) | (exposition only*) |
template<class R,class T> concept/*container-compatible-range*/= | (8) | (exposition only*) |
The overloads of the range conversion function construct a new non-view object from a source range as its first argument by calling a constructor taking a range, astd::from_range_t
tagged ranged constructor, a constructor taking an iterator-sentinel pair, or by back inserting each element of the source range into the arguments-constructed object.
C
from the elements ofr in the following:C
does not satisfyinput_range
orstd::convertible_to<ranges::range_reference_t<R>,ranges::range_value_t<C>> istrue:C
from the source rangestd::forward<R>(r) and the rest of the functional argumentsstd::forward<Args>(args)... ifstd::constructible_from<C, R, Args...> istrue.C
from additional disambiguation tagstd::from_range, the source rangestd::forward<R>(r) and the rest of the functional argumentsstd::forward<Args>(args)... ifstd::constructible_from<C,std::from_range_t, R, Args...> istrue.C
from the iterator-sentinel pair (ranges::begin(r) as an iterator andranges::end(r) as sentinel, where iterator and sentinel have the same type. In other words, the source range must be a common range), and the rest of function argumentsstd::forward<Args>(args)... if all of the conditions below aretrue:C
from the rest of the function argumentsstd::forward<Args>(args)... with the following equivalent call below after the construction:ifconstexpr(ranges::sized_range<R>&&/*reservable-container*/<C>) | (until C++26) |
ifconstexpr(ranges::approximately_sized_range<R> | (since C++26) |
R
satisfiessized_range
(until C++26)approximately_sized_range
(since C++26) andC
satisfiesreservable-container
, the constructed objectc of typeC
is able to reserve storage with the initial storage sizeranges::size(r)(until C++26)ranges::reserve_hint(r)(since C++26) to prevent additional allocations during inserting new elements. Each element ofr is appended toc.The operations above are valid if both of the conditions below aretrue:
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)...)
Which allows nested range constructions within the range ifranges::input_range<ranges::range_reference_t<C>> istrue.
Let/*input-iterator*/ be an exposition only type that satisfiesLegacyInputIterator:
struct/*input-iterator*/ { | (exposition only*) | |
Let/*DEDUCE-EXPR*/ be defined as follows:
Reference
can be appended toContainer
through a member function callemplace_back
,push_back
,emplace
orinsert
.return[&c]<class Reference>(Reference&& ref)
{
ifconstexpr(requires{ c.emplace_back(std::declval<Reference>());})
c.emplace_back(std::forward<Reference>(ref));
elseifconstexpr(requires{ c.push_back(std::declval<Reference>());})
c.push_back(std::forward<Reference>(ref));
elseifconstexpr(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
whose range reference type must be convertible toT
.Contents |
r | - | a source range object |
args | - | list of the arguments to(1,2) construct a range or(3,4) bind to the last parameters of range adaptor closure object |
Type requirements | ||
-C must be cv-unqualified class type(1,3) |
The returned object behaves as if it has no target object, and anstd::tuple objecttup constructed withstd::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...), except that the returned object's assignment behavior is unspecified and the names are for exposition only.
The return type ofranges::to
(3,4) behaves as if its copy/move constructors perform a memberwise copy/move. It isCopyConstructible if all of its member objects (specified above) areCopyConstructible, and isMoveConstructible otherwise.
operator()
Given an objectG
obtained from an earlier call torange::to</* see below */>(args...), when a glvalueg designatingG
is invoked in a function call expressiong(r), an invocation of the stored object takes place, as if by
input_range
.C
or(4) the deduced type from a class templateC
that must not satisfyview
.The program is ill-formed ifg has volatile-qualified type.
Only throws if construction of a non-view object throws.
The insertion of elements into the container may involve copy which can be less efficient than move because lvalue references are produced during the indirection call. Users can opt-in to useviews::as_rvalue to adapt the range in order for their elements to always produce an rvalue reference during the indirection call which implies move.
The parentheses are mandatory when using the pipe syntax.
auto vec= r| std::ranges::to<std::vector>;// Errorauto vec= r| std::ranges::to<std::vector>();// OK
Feature-test macro | Value | 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, andchanges tostd::ranges::to |
A preview link: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(constauto& v){std::ostringstream out; out<<'[';for(int n{};constauto& e: v) out<<(n++?", ":"")<< e; out<<']';return out;} template<typename T>structstd::formatter<std::vector<T>,char>{template<class ParseContext>constexpr ParseContext::iterator parse(ParseContext& ctx){return ctx.begin();} template<class FmtContext> FmtContext::iterator format(autoconst& s, FmtContext& ctx)const{auto out{print_aid(s)};return std::ranges::copy(std::move(out).str(), ctx.out()).out;}}; template<typename T>structstd::formatter<std::list<T>,char>{template<class ParseContext>constexpr ParseContext::iterator parse(ParseContext& ctx){return ctx.begin();} template<class FmtContext> FmtContext::iterator format(autoconst& 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 tostd::string str(array); // Result type is not an input range:auto re_to= std::ranges::to<std::regex>(array);// Equivalent tostd::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 tostd::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 tostd::cregex_iterator it(std::ranges::begin(list), std::ranges::end(list), re);}}
Output:
[2, 4, 6, 8][2, 4, 6]
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 3984 | C++23 | the nested construction branch ofranges::to resulted toprogram ill-formed if R& does not modelviewable_range | made well-formed |
LWG 4016 | C++23 | the container insertion branch ofranges::to involved use of insert iterators | replaced with direct appending of elements to container |