Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/ranges"

From cppreference.com
< cpp
m (fmt)
m (Other utilities: +ranges::elements_of.)
 
(45 intermediate revisions by 7 users not shown)
Line 5: Line 5:
  
 
The library creates and manipulates range ''views'', lightweight objects that indirectly represent iterable sequences (''ranges''). Ranges are an abstraction on top of
 
The library creates and manipulates range ''views'', lightweight objects that indirectly represent iterable sequences (''ranges''). Ranges are an abstraction on top of
* [begin, end) iterator pairs, e.g. ranges made by implicit conversion from containers. All algorithms that take iterator pairs now have overloads that accept ranges (e.g {{ltt|cpp/algorithm/ranges/sort|ranges::sort}})
+
* {{range/core|begin|end}} &ndash; iterator pairs, e.g. ranges made by implicit conversion from containers. All algorithms that take iterator pairs now have overloads that accept ranges (e.g. {{ltt|cpp/algorithm/ranges/sort|ranges::sort}})
* [start, size) counted sequences, e.g. range returned by {{ltt|cpp/ranges/view_counted|views::counted}}
+
* {{counted range/core|begin|size}} &ndash; counted sequences, e.g. range returned by {{ltt|cpp/ranges/view_counted|views::counted}}
* [start, predicate) conditionally-terminated sequences, e.g. range returned by {{ltt|cpp/ranges/take_while_view|views::take_while}}
+
* {{range/core|begin|''predicate''}} &ndash; conditionally-terminated sequences, e.g. range returned by {{ltt|cpp/ranges/take_while_view|views::take_while}}
* [start..) unbounded sequences, e.g. range returned by {{ltt|cpp/ranges/iota_view|views::iota}}
+
* {{range/core|begin|..}} &ndash; unbounded sequences, e.g. range returned by {{ltt|cpp/ranges/iota_view|views::iota}}
  
The ranges library includes [[cpp/algorithm/ranges|range algorithms]], which are applied to ranges eagerly, and [[cpp/ranges#Range adaptors|range adaptors]], which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated.
+
The ranges library includes [[cpp/algorithm/ranges|range algorithms]], which are applied to ranges eagerly, and {{lsd|#Range adaptors}}, which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated.
  
 
{{ddcl|header=ranges|since=c++20|1=
 
{{ddcl|header=ranges|since=c++20|1=
Line 41: Line 41:
 
{{dsc header|ranges}}
 
{{dsc header|ranges}}
 
{{dsc inc|cpp/ranges/dsc iterator_t}}
 
{{dsc inc|cpp/ranges/dsc iterator_t}}
 +
{{dsc inc|cpp/ranges/dsc range_size_t}}
 +
{{dsc inc|cpp/ranges/dsc range_reference_t}}
 
{{dsc h2|Dangling iterator handling}}
 
{{dsc h2|Dangling iterator handling}}
 
{{dsc header|ranges}}
 
{{dsc header|ranges}}
 
{{dsc inc|cpp/ranges/dsc dangling}}
 
{{dsc inc|cpp/ranges/dsc dangling}}
 
{{dsc inc|cpp/ranges/dsc borrowed_iterator_t}}
 
{{dsc inc|cpp/ranges/dsc borrowed_iterator_t}}
 +
{{dsc h2|Other utilities}}
 +
{{dsc header|ranges}}
 +
{{dsc inc|cpp/ranges/dsc elements_of}}
 
{{dsc h2|Range concepts}}
 
{{dsc h2|Range concepts}}
 
{{dsc header|ranges}}
 
{{dsc header|ranges}}
Line 76: Line 81:
 
{{dsc inc|cpp/ranges/dsc single_view}}
 
{{dsc inc|cpp/ranges/dsc single_view}}
 
{{dsc inc|cpp/ranges/dsc iota_view}}
 
{{dsc inc|cpp/ranges/dsc iota_view}}
{{dsc inc|cpp/ranges/dsc basic_istream_view}}
 
 
{{dsc inc|cpp/ranges/dsc repeat_view}}
 
{{dsc inc|cpp/ranges/dsc repeat_view}}
{{dsc inc|cpp/ranges/dsc cartesian_product_view}}
+
{{dsc inc|cpp/ranges/dsc basic_istream_view}}
 
{{dsc end}}
 
{{dsc end}}
  
Line 85: Line 89:
 
{{dsc header|ranges}}
 
{{dsc header|ranges}}
 
{{dsc namespace|std::ranges}}
 
{{dsc namespace|std::ranges}}
 +
{{dsc inc|cpp/ranges/dsc range_adaptor_closure}}
 
{{dsc inc|cpp/ranges/dsc all_view}}
 
{{dsc inc|cpp/ranges/dsc all_view}}
 
{{dsc inc|cpp/ranges/dsc ref_view}}
 
{{dsc inc|cpp/ranges/dsc ref_view}}
 
{{dsc inc|cpp/ranges/dsc owning_view}}
 
{{dsc inc|cpp/ranges/dsc owning_view}}
 +
{{dsc inc|cpp/ranges/dsc as_rvalue_view}}
 
{{dsc inc|cpp/ranges/dsc filter_view}}
 
{{dsc inc|cpp/ranges/dsc filter_view}}
 
{{dsc inc|cpp/ranges/dsc transform_view}}
 
{{dsc inc|cpp/ranges/dsc transform_view}}
Line 95: Line 101:
 
{{dsc inc|cpp/ranges/dsc drop_while_view}}
 
{{dsc inc|cpp/ranges/dsc drop_while_view}}
 
{{dsc inc|cpp/ranges/dsc join_view}}
 
{{dsc inc|cpp/ranges/dsc join_view}}
{{dsc inc|cpp/ranges/dsc split_view}}
+
{{dsc inc|cpp/ranges/dsc join_with_view}}
 
{{dsc inc|cpp/ranges/dsc lazy_split_view}}
 
{{dsc inc|cpp/ranges/dsc lazy_split_view}}
 +
{{dsc inc|cpp/ranges/dsc split_view}}
 +
{{dsc inc|cpp/ranges/dsc concat_view}}
 
{{dsc inc|cpp/ranges/dsc view_counted}}
 
{{dsc inc|cpp/ranges/dsc view_counted}}
 
{{dsc inc|cpp/ranges/dsc common_view}}
 
{{dsc inc|cpp/ranges/dsc common_view}}
 
{{dsc inc|cpp/ranges/dsc reverse_view}}
 
{{dsc inc|cpp/ranges/dsc reverse_view}}
 +
{{dsc inc|cpp/ranges/dsc as_const_view}}
 
{{dsc inc|cpp/ranges/dsc elements_view}}
 
{{dsc inc|cpp/ranges/dsc elements_view}}
 
{{dsc inc|cpp/ranges/dsc keys_view}}
 
{{dsc inc|cpp/ranges/dsc keys_view}}
 
{{dsc inc|cpp/ranges/dsc values_view}}
 
{{dsc inc|cpp/ranges/dsc values_view}}
 +
{{dsc inc|cpp/ranges/dsc enumerate_view}}
 
{{dsc inc|cpp/ranges/dsc zip_view}}
 
{{dsc inc|cpp/ranges/dsc zip_view}}
 
{{dsc inc|cpp/ranges/dsc zip_transform_view}}
 
{{dsc inc|cpp/ranges/dsc zip_transform_view}}
 
{{dsc inc|cpp/ranges/dsc adjacent_view}}
 
{{dsc inc|cpp/ranges/dsc adjacent_view}}
 
{{dsc inc|cpp/ranges/dsc adjacent_transform_view}}
 
{{dsc inc|cpp/ranges/dsc adjacent_transform_view}}
{{dsc inc|cpp/ranges/dsc join_with_view}}
 
{{dsc inc|cpp/ranges/dsc slide_view}}
 
 
{{dsc inc|cpp/ranges/dsc chunk_view}}
 
{{dsc inc|cpp/ranges/dsc chunk_view}}
 +
{{dsc inc|cpp/ranges/dsc slide_view}}
 
{{dsc inc|cpp/ranges/dsc chunk_by_view}}
 
{{dsc inc|cpp/ranges/dsc chunk_by_view}}
{{dsc inc|cpp/ranges/dsc as_const_view}}
 
{{dsc inc|cpp/ranges/dsc as_rvalue_view}}
 
 
{{dsc inc|cpp/ranges/dsc stride_view}}
 
{{dsc inc|cpp/ranges/dsc stride_view}}
 +
{{dsc inc|cpp/ranges/dsc cartesian_product_view}}
 
{{dsc end}}
 
{{dsc end}}
  
Some range adaptors wrap their elements or function objects with the [[cpp/ranges/copyable_wrapper|''copyable wrapper'']].
+
===Range generators===
 +
{{dsc begin}}
 +
{{dsc header|generator}}
 +
{{dsc namespace|std}}
 +
{{dsc inc|cpp/ranges/dsc generator}}
 +
{{dsc end}}
  
====Range adaptor closure objects====
+
===Helper items===
''Range adaptor closure objects'' are objects whose type is the same as one of the following objects (ignoring cv-qualification):
+
* unary range adaptor objects,
+
{{rrev|since=c++23|
+
* objects of user-defined types other than unary range adaptor objects who meet the requirements of implementing a range adaptor closure object,
+
}}
+
* the results of binding trailing arguments by range adaptor objects, and
+
* the results of chaining two range adaptor closure objects by {{c|operator{{!}}}}.
+
  
Range adaptor closure objects take one {{rev inl|until=c++23|{{lconcept|viewable_range}}}} {{rev inl|since=c++23|{{lconcept|range}}}} as its only argument {{rev inl|until=c++23|and returns a {{lconcept|view}}}}. They are callable via the pipe operator: if {{c|C}} is a range adaptor closure object and {{c|R}} is a {{rev inl|until=c++23|{{lconcept|viewable_range}}}} {{rev inl|since=c++23|{{lconcept|range}}}}, these two expressions are equivalent (both well-formed or ill-formed):
+
====Range adaptor objects====
{{source|1=
+
See {{named req|RangeAdaptorObject}} (RAO).
C(R)
+
R {{!}} C
+
}}
+
  
This call forwards the bound arguments (if any) to the associated range adaptor object. The bound arguments (if any) are identically treated as lvalue or rvalue and cv-qualified to {{c|C}}.
+
====Range adaptor closure objects====
 +
See {{named req|RangeAdaptorClosureObject}} (RACO).
  
Two range adaptor closure objects can be chained by {{c|operator{{!}}}} to produce another range adaptor closure object: if {{c|C}} and {{c|D}} are range adaptor closure objects, then {{c|C {{!}} D}} is also a range adaptor closure object if it is valid.
+
====Customization point objects====
 +
See {{rl|cpo|Customization point object}} (CPO).
  
The bound arguments of {{c|C {{!}} D}} is determined as follows:
+
====Assignable wrapper====
* there is a subobject in the result object of the same type (cv-qualification discarded) for every subobject in both operands that is a bound argument,
+
Some range adaptors wrap their elements or function objects with the {{rev inl|until=c++23|{{rli|copyable wrapper|copyable-box}}}}{{rev inl|since=c++23|{{rli|copyable wrapper|movable-box}}}}. The wrapper augments the wrapped object with assignability when needed.<!--TODO: update the internal link to "movable_wrapper". -->
* such a bound argument is direct-non-list-initialized with the source subobject in its containing operand, where the source is identically treated as lvalue or rvalue and cv-qualified to the operand,
+
* the result is valid if and only if the initialization of all bound arguments are valid.
+
  
The effect and validity of the {{c|operator()}} of the result is determined as follows: given a {{rev inl|until=c++23|{{lconcept|viewable_range}}}} {{rev inl|since=c++23|{{lconcept|range}}}} {{c|R}}, these two expressions are equivalent (both well-formed or ill-formed):
+
====Non-propagating cache====
{{source|1=
+
Some range adaptors are specified in terms of an exposition-only class template {{rli|non-propagating-cache}}, which behaves almost like {{c/core|std::optional<T>}} (see description for differences).
R {{!}} C {{!}} D // (R {{!}} C) {{!}} D
+
 
R {{!}} (C {{!}} D)
+
====Conditionally-{{tt|const}} type====
 +
{{dcl begin}}
 +
{{dcla|anchor=maybe-const|expos=yes|1=
 +
template< bool Const, class T >
 +
using /*maybe-const*/ = std::conditional_t<Const, const T, T>;
 
}}
 
}}
 +
{{dcl end}}
  
Notes: {{c|operator()}} is unsupported for volatile-qualified or const-volatile-qualified version of range adaptor object closure types.
+
The alias template {{c/core|/*maybe-const*/}} is a shorthand used to conditionally apply a {{c/core|const}} qualifier to the type {{tt|T}}.
  
{{rrev|since=c++23|
+
====Integer-like type helper templates====
Let {{tt|t}} be the object of type {{tt|T}}, then {{tt|t}} is a range adaptor closure object if all the requirements are met:
+
{{dcl begin}}
* {{tt|t}} is a unary function object that takes one {{lconcept|range}} argument.
+
{{dcla|num=1|anchor=make-signed-like-t|expos=yes|1=
* {{tt|T}} has exactly one public base class {{c|ranges::range_adaptor_closure<T>}}, and {{c|T}} has no base classes of type {{c|ranges::range_adaptor_closure<U>}} for any other type {{c|U}}.
+
template< /*is-integer-like*/ T >
* {{tt|T}} does not satisfy {{lconcept|range}}.
+
using /*make-signed-like-t*/<T> = /* see description */;
 +
}}
 +
{{dcla|num=2|anchor=make-unsigned-like-t|expos=yes|1=
 +
template< /*is-integer-like*/ T >
 +
using /*make-unsigned-like-t*/<T> = /* see description */;
 +
}}
 +
{{dcla|num=3|anchor=to-unsigned-like|expos=yes|
 +
template< /*is-integer-like*/ T >
 +
/*make-unsigned-like-t*/<T> /*to-unsigned-like*/( T t )
 +
{
 +
    return static_cast</*make-unsigned-like-t*/<T>>(t);
 +
}
 +
}}
 +
{{dcl end}}
  
One can create a user-defined range adaptor closure object by following the requirements above.
+
@1@ For an [[cpp/iterator/is-integer-like|integer-like type]] {{tt|T}}:
{{example|code=
+
* If {{tt|T}} is an integer type, {{c/core|/*make-signed-like-t*/<T>}} is {{c/core|std::make_signed_t<T>}}.
#include <ranges>
+
* Otherwise, {{c/core|/*make-signed-like-t*/<T>}} is a corresponding unspecified signed-integer-like type of the same width as {{tt|T}}.
#include <algorithm>
+
  
struct TakeTripleAndReverse
+
@2@ For an integer-like type {{tt|T}}:
: std::ranges::range_adaptor_closure<TakeTripleAndReverse>
+
* If {{tt|T}} is an integer type, {{c/core|/*make-unsigned-like-t*/<T>}} is {{c/core|std::make_unsigned_t<T>}}.
{
+
* Otherwise, {{c/core|/*make-signed-like-t*/<T>}} is a corresponding unspecified unsigned-integer-like type of the same width as {{tt|T}}.
    template <std::ranges::viewable_range R>
+
        requires std::ranges::bidirectional_range<R>
+
    constexpr auto operator()(R&& r) const
+
    {
+
        return std::forward<R>(r) {{!}} std::views::take(3)
+
                                  {{!}} std::views::reverse;
+
    }
+
};
+
  
inline constexpr TakeTripleAndReverse take_triple_and_reverse {};
+
@3@ Explicitly converts {{c|t}} to {{c/core|/*make-unsigned-like-t*/<T>}}.
  
template <typename R, typename T>
+
====Customization point object helpers====
constexpr bool equal_to(R&& r, std::initializer_list<T> il)  
+
{{dcl begin}}
 +
{{dcla|num=1|anchor=possibly-const-range|expos=yes|
 +
template< ranges::input_range R >
 +
constexpr auto& /*possibly-const-range*/(R& r) noexcept
 
{
 
{
     return std::ranges::equal(r, il);
+
     if constexpr (ranges::constant_range<const R> &&
 +
                  !ranges::constant_range<R>)
 +
        return const_cast<const R&>(r);
 +
    else
 +
        return r;
 
}
 
}
 
+
}}
int main()  
+
{{dcla|num=2|anchor=as-const-pointer|expos=yes|
 +
template< class T >
 +
constexpr auto /*as-const-pointer*/( const T* p ) noexcept
 
{
 
{
     static constexpr int arr[] = {6, 2, 8, 4, 4, 2};
+
     return p;
    static constexpr auto plus_one = std::views::transform([](int n){ return n + 1; });
+
 
+
    static_assert(equal_to(take_triple_and_reverse(arr), {8, 2, 6}));
+
    static_assert(equal_to(arr {{!}} take_triple_and_reverse, {8, 2, 6}));
+
    static_assert(equal_to(arr {{!}} take_triple_and_reverse {{!}} plus_one, {9, 3, 7}));
+
    static_assert(equal_to(arr {{!}} plus_one {{!}} take_triple_and_reverse, {9, 3, 7}));
+
 
}
 
}
 
}}
 
}}
}}
+
{{dcl end}}
  
====Range adaptor objects====
+
Some range access customization point objects are specified in terms of these exposition-only function templates.
''Range adaptor objects'' are customization point objects that accept {{lconcept|viewable_range}} as their first arguments and return a {{lconcept|view}}. Some range adaptor objects are unary, i.e. they take one {{lconcept|viewable_range}} as their only argument. Other range adaptor objects take a {{lconcept|viewable_range}} and other trailing arguments.
+
  
If a range adaptor object takes more than one argument, it also supports partial application: let
+
@1@ {{c/core|/*possibly-const-range*/}} returns a const-qualified range {{c|r}} if it is a "deep-const" range; otherwise, returns {{c|r}} without any casting.
* {{c|a}} be such a range adaptor object, and
+
* {{c|args...}} be arguments (generally suitable for trailing arguments),
+
expression {{c|a(args...)}} has following properties:
+
* it is valid if and only if for every argument {{c|e}} in {{c|args...}} such that {{tt|E}} is {{c|decltype((e))}}, {{c|std::is_constructible_v<std::decay_t<E>, E>}} is {{c|true}},
+
* when the call is valid, its result object stores a subobject of type {{c|std::decay_t<E>}} direct-non-list-initialized with {{c|std::forward<E>(e)}}, for every argument {{c|e}} in {{c|args...}} (in other words, range adaptor objects bind arguments by value), and
+
* the result object is a [[#Range adaptor closure objects|range adaptor closure object]].
+
  
Like other customization point objects, let
+
@2@ {{c/core|/*as-const-pointer*/}} returns a pointer to object of constant type.
* {{c|a}} be an object of the cv-unqualified version of the type of any range adaptor objects,
+
* {{c|args...}} be any group of arguments that satisfies the constraints of the {{c|operator()}} of the type of {{c|a}},
+
calls to
+
* {{c|a(args...)}},
+
* {{c|std::as_const(a)(args...)}},
+
* {{c|std::move(a)(args...)}}, and
+
* {{c|std::move(std::as_const(a))(args...)}}
+
are all equivalent.
+
  
The result object of each of these expressions is either a {{lconcept|view}} object or a range adaptor closure object.
+
====Range adaptor helpers====
 +
{{dcl begin}}
 +
{{dcla|num=1|anchor=tuple-transform|expos=yes|
 +
template< class F, class Tuple >
 +
constexpr auto /*tuple-transform*/( F&& f, Tuple&& tuple )
 +
{
 +
    return std::apply([&]<class... Ts>(Ts&&... args)
 +
    {
 +
        return std::tuple<std::invoke_result_t<F&, Ts>...>
 +
            (std::invoke(f, std::forward<Ts>(args))...);
 +
    }, std::forward<Tuple>(tuple));
 +
}
 +
}}
 +
{{dcla|num=2|anchor=tuple-for-each|expos=yes|
 +
template< class F, class Tuple >
 +
constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple )
 +
{
 +
    std::apply([&]<class... Ts>(Ts&&... args)
 +
    {
 +
        (static_cast<void>(std::invoke(f, std::forward<Ts>(args))), ...);
 +
    }, std::forward<Tuple>(tuple));
 +
}
 +
}}
 +
{{dcla|num=3|anchor=as-lvalue|expos=yes|
 +
template< class T >
 +
constexpr T& /*as-lvalue*/( T&& t )
 +
{
 +
    return static_cast<T&>(t);
 +
}
 +
}}
 +
{{dcl end}}
  
Notes: {{c|operator()}} is unsupported for volatile-qualified or const-volatile-qualified version of range adaptor object types. Arrays and functions are converted to pointers while binding.
+
Some range adaptors are specified in terms of these exposition-only function templates.
  
===Helper concepts===
+
@1@ {{c/core|/*tuple-transform*/}} returns a new tuple constructed by applying {{c|f}} to each element of {{c|tuple}}.
 +
@2@ {{c/core|/*tuple-for-each*/}} applies {{c|f}} to each element of {{c|tuple}} and returns nothing.
 +
@3@ {{c/core|/*as-lvalue*/}} forwards rvalue {{c|t}} as lvalue.
 +
 
 +
====Helper concepts====
 
Following exposition-only concepts are used for several types, but they are not parts of the interface of standard library.
 
Following exposition-only concepts are used for several types, but they are not parts of the interface of standard library.
  
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl|1=<!-- called simple-view in the standard -->
+
{{dcla|num=1|anchor=simple-view|expos=yes|1=
template<class R>
+
template< class R >
  concept __simple_view =                    // exposition only
+
concept /*simple-view*/ =
 
     ranges::view<R> && ranges::range<const R> &&
 
     ranges::view<R> && ranges::range<const R> &&
     std::same_as<std::ranges::iterator_t<R>, std::ranges::iterator_t<const R>> &&
+
     std::same_as<ranges::iterator_t<R>, ranges::iterator_t<const R>> &&
     std::same_as<std::ranges::sentinel_t<R>, std::ranges::sentinel_t<const R>>;
+
    std::same_as<ranges::sentinel_t<R>, ranges::sentinel_t<const R>>;
 +
}}
 +
{{dcla|num=2|anchor=has-arrow|expos=yes|1=
 +
template< class I >
 +
concept /*has-arrow*/ =
 +
    ranges::input_iterator<I> &&
 +
     (std::is_pointer_v<I> {{!!}} requires(I i) { i.operator->(); });
 +
}}
 +
{{dcla|num=3|anchor=different-from|expos=yes|1=
 +
template< class T, class U >
 +
concept /*different-from*/ =
 +
    !std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
 +
}}
 +
{{dcla|num=4|anchor=range-with-movable-references|expos=yes|1=
 +
template< class R >
 +
concept /*range-with-movable-references*/ =
 +
    ranges::input_range<R> &&
 +
    std::move_constructible<ranges::range_reference_t<R>> &&
 +
    std::move_constructible<ranges::range_rvalue_reference_t<R>>;
 +
}}
 +
{{dcla|num=5|anchor=all-random-access|expos=yes|1=
 +
template< bool C, class... Views >
 +
concept /*all-random-access*/ =
 +
    (ranges::random_access_range
 +
        <std::conditional_t<C, const Views, Views>> && ...);
 +
}}
 +
{{dcla|num=6|anchor=all-bidirectional|expos=yes|1=
 +
template< bool C, class... Views >
 +
concept /*all-bidirectional*/ =
 +
    (ranges::bidirectional_range
 +
        <std::conditional_t<C, const Views, Views>> && ...);
 +
}}
 +
{{dcla|num=7|anchor=all-forward|expos=yes|1=
 +
template< bool C, class... Views >
 +
concept /*all-forward*/ =
 +
    (ranges::forward_range
 +
        <std::conditional_t<C, const Views, Views>> && ...);
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
Line 234: Line 304:
 
===Notes===
 
===Notes===
 
{{ftm begin|std=1|sort=1|comment=1}}
 
{{ftm begin|std=1|sort=1|comment=1}}
{{ftm|value=201911L|std=C++20|__cpp_lib_ranges|rowspan="5"|[[cpp/ranges|Ranges library]] and [[cpp/algorithm/ranges|constrained algorithms]]}}
+
{{ftm|value=202207L|std=C++23|__cpp_lib_generator|{{c/core|std::generator}} – synchronous coroutine generator for ranges}}
{{ftm|value=202106L|std=C++20)<br>(DR|-|Non-[[cpp/concepts/default_initializable|default-initializable]] [[cpp/ranges/view|view]]s}}
+
{{ftm|value=201911L|std=C++20|__cpp_lib_ranges|rowspan="8"|Ranges library and [[cpp/algorithm/ranges|constrained algorithms]]}}
{{ftm|value=202110L|std=C++20)<br>(DR|-|[[cpp/ranges/view|View]]s with [[cpp/ranges/owning_view|ownership]]}}
+
{{ftm|value=202106L|std=C++20|-|Non-[[cpp/concepts/default initializable|default-initializable]] [[cpp/ranges/view|view]]s|dr=yes}}
{{ftm|value=202202L|std=C++23|-|{{lc|std::ranges::range_adaptor_closure}}}}
+
{{ftm|value=202110L|std=C++20|-|[[cpp/ranges/view|View]]s with [[cpp/ranges/owning_view|ownership]]|dr=yes}}
{{ftm|value=202207L|std=C++23|-|Relaxing [[#Range adaptors|range adaptors]] to allow for move only types}}
+
{{ftm|value=202202L|std=C++23|-|{{c/core|ranges::range_adaptor_closure}}}}
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_as_const|{{lc|std::const_iterator}}, {{lc|std::ranges::as_const_view}}}}
+
{{ftm|value=202207L|std=C++23|-|Relaxing {{lsd|#Range adaptors}} to allow for move-only types}}
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_as_rvalue|{{lc|std::ranges::as_rvalue_view}}}}
+
{{ftm|value=202211L|std=C++23|-|Removing "poison pills" {{stddoc|p2602|(P2602)}} overloads in {{c/core|ranges::begin}} etc}}
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_cartesian_product|{{lc|std::ranges::cartesian_product_view}}}}
+
{{ftm|value=202302L|std=C++23|-|Relaxing ranges to allow certain projections}}
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_chunk|{{lc|std::ranges::chunk_view}}}}
+
{{ftm|value=202406L|std=C++20|-|Removing the common reference requirement from the indirectly invocable concepts|dr=yes}}
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_chunk_by|{{lc|std::ranges::chunk_by_view}}}}
+
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_as_const|{{c/core|std::const_iterator}}, {{c/core|ranges::as_const_view}}}}
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_join_with|{{lc|std::ranges::join_with_view}}}}
+
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_as_rvalue|{{c/core|ranges::as_rvalue_view}}}}
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_repeat|{{lc|std::ranges::repeat_view}}}}
+
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_cartesian_product|{{c/core|ranges::cartesian_product_view}}}}
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_slide|{{lc|std::ranges::slide_view}}}}
+
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_chunk|{{c/core|ranges::chunk_view}}}}
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_stride|{{lc|std::ranges::stride_view}}}}
+
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_chunk_by|{{c/core|ranges::chunk_by_view}}}}
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_to_container|{{lc|std::ranges::to}}}}
+
{{ftm|value=202403L|std=C++26|__cpp_lib_ranges_concat|{{c/core|ranges::concat_view}}}}
{{ftm|value=202110L|std=C++23|__cpp_lib_ranges_zip|{{lc|std::ranges::zip_view}}, {{lc|std::ranges::zip_transform_view}}, {{lc|std::ranges::adjacent_view}}, {{lc|std::ranges::adjacent_transform_view}}}}
+
{{ftm|value=202302L|std=C++23|__cpp_lib_ranges_enumerate|{{c/core|ranges::enumerate_view}}}}
 +
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_join_with|{{c/core|ranges::join_with_view}}}}
 +
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_repeat|{{c/core|ranges::repeat_view}}}}
 +
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_slide|{{c/core|ranges::slide_view}}}}
 +
{{ftm|value=202207L|std=C++23|__cpp_lib_ranges_stride|{{c/core|ranges::stride_view}}}}
 +
{{ftm|value=202202L|std=C++23|__cpp_lib_ranges_to_container|{{c/core|ranges::to}}}}
 +
{{ftm|value=202110L|std=C++23|__cpp_lib_ranges_zip|{{c/core|ranges::zip_view}},<br>{{c/core|ranges::zip_transform_view}},<br>{{c/core|ranges::adjacent_view}},<br>{{c/core|ranges::adjacent_transform_view}}}}
 
{{ftm end}}
 
{{ftm end}}
  
Line 262: Line 338:
 
     auto even = [](int i) { return 0 == i % 2; };
 
     auto even = [](int i) { return 0 == i % 2; };
 
     auto square = [](int i) { return i * i; };
 
     auto square = [](int i) { return i * i; };
 
+
   
 
     // the "pipe" syntax of composing the views:
 
     // the "pipe" syntax of composing the views:
 
     for (int i : ints {{!}} std::views::filter(even) {{!}} std::views::transform(square))
 
     for (int i : ints {{!}} std::views::filter(even) {{!}} std::views::transform(square))
 
         std::cout << i << ' ';
 
         std::cout << i << ' ';
 
+
   
 
     std::cout << '\n';
 
     std::cout << '\n';
 
+
   
 
     // a traditional "functional" composing syntax:
 
     // a traditional "functional" composing syntax:
 
     for (int i : std::views::transform(std::views::filter(ints, even), square))
 
     for (int i : std::views::transform(std::views::filter(ints, even), square))
Line 280: Line 356:
 
===Defect reports===
 
===Defect reports===
 
{{dr list begin}}
 
{{dr list begin}}
{{dr list item|wg=lwg|dr=3509<!-- P2281R1 --->|std=C++20|before=it was unclear how range adaptor objects bound trailing arguments|after=they are bound by value}}
+
{{dr list item|wg=lwg|dr=3509|paper=P2281R1|std=C++20|before=it was unclear how range adaptor objects bound trailing arguments|after=they are bound<br>by value}}
 +
{{dr list item|wg=lwg|dr=3948|std=C++23|before={{tti|possibly-const-range}} and {{tti|as-const-pointer}} were not declared {{c/core|noexcept}}|after=declared {{c/core|noexcept}}}}
 
{{dr list end}}
 
{{dr list end}}
  
 
===See also===
 
===See also===
* {{named req|RangeAdaptorObject}}
+
* [[cpp/iterator|Iterator library]]
* {{named req|RangeAdaptorClosureObject}}
+
* [[cpp/algorithm/ranges|Constrained algorithms]]
  
 
{{langlinks|es|ja|ru|zh}}
 
{{langlinks|es|ja|ru|zh}}

Latest revision as of 08:31, 10 September 2024

 
 
Ranges library
Range adaptors
 

The ranges library is an extension and generalization of the algorithms and iterator libraries that makes them more powerful by making them composable and less error-prone.

The library creates and manipulates range views, lightweight objects that indirectly represent iterable sequences (ranges). Ranges are an abstraction on top of

  • [beginend) – iterator pairs, e.g. ranges made by implicit conversion from containers. All algorithms that take iterator pairs now have overloads that accept ranges (e.g. ranges::sort)
  • begin + [0size) – counted sequences, e.g. range returned by views::counted
  • [beginpredicate) – conditionally-terminated sequences, e.g. range returned by views::take_while
  • [begin..) – unbounded sequences, e.g. range returned by views::iota

The ranges library includes range algorithms, which are applied to ranges eagerly, and range adaptors, which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated.

Defined in header <ranges>
namespace std {

    namespace views = ranges::views;

}
(since C++20)

The namespace alias std::views is provided as a shorthand for std::ranges::views.

Defined in namespace std::ranges

Contents

Range access
Defined in header <ranges>
Defined in header <iterator>
returns an iterator to the beginning of a range
(customization point object)[edit]
returns a sentinel indicating the end of a range
(customization point object)[edit]
returns an iterator to the beginning of a read-only range
(customization point object)[edit]
returns a sentinel indicating the end of a read-only range
(customization point object)[edit]
returns a reverse iterator to a range
(customization point object)[edit]
returns a reverse end iterator to a range
(customization point object)[edit]
returns a reverse iterator to a read-only range
(customization point object)[edit]
returns a reverse end iterator to a read-only range
(customization point object)[edit]
returns an integer equal to the size of a range
(customization point object)[edit]
returns a signed integer equal to the size of a range
(customization point object)[edit]
checks whether a range is empty
(customization point object)[edit]
obtains a pointer to the beginning of a contiguous range
(customization point object)[edit]
obtains a pointer to the beginning of a read-only contiguous range
(customization point object)[edit]
Range primitives
Defined in header <ranges>
obtains iterator and sentinel types of a range
(alias template)[edit]
obtains size, difference, and value types of a range
(alias template)[edit]
obtains reference types of a range
(alias template)[edit]
Dangling iterator handling
Defined in header <ranges>
a placeholder type indicating that an iterator or a subrange should not be returned since it would be dangling
(class) [edit]
obtains iterator type or subrange type of a borrowed_range
(alias template)[edit]
Other utilities
Defined in header <ranges>
tags a range to be treated as a sequence rather than a single value
(class template) [edit]
Range concepts
Defined in header <ranges>
specifies that a type is a range, that is, it provides a begin iterator and an end sentinel
(concept) [edit]
specifies that a type is a range and iterators obtained from an expression of it can be safely returned without danger of dangling
(concept) [edit]
specifies that a range knows its size in constant time
(concept) [edit]
specifies that a range is a view, that is, it has constant time copy/move/assignment
(concept) [edit]
specifies a range whose iterator type satisfies input_iterator
(concept) [edit]
specifies a range whose iterator type satisfies output_iterator
(concept) [edit]
specifies a range whose iterator type satisfies forward_iterator
(concept) [edit]
specifies a range whose iterator type satisfies bidirectional_iterator
(concept) [edit]
specifies a range whose iterator type satisfies random_access_iterator
(concept) [edit]
specifies a range whose iterator type satisfies contiguous_iterator
(concept) [edit]
specifies that a range has identical iterator and sentinel types
(concept) [edit]
specifies the requirements for a range to be safely convertible to a view
(concept) [edit]
specifies that a range has read-only elements
(concept) [edit]
Range conversions
Defined in header <ranges>
constructs a new non-view object from an input range
(function template) [edit]
Views
Defined in header <ranges>
helper class template for defining a view, using the curiously recurring template pattern
(class template) [edit]
combines an iterator-sentinel pair into a view
(class template) [edit]

[edit] Range factories

Defined in header <ranges>
Defined in namespace std::ranges
an empty view with no elements
(class template) (variable template)[edit]
a view that contains a single element of a specified value
(class template) (customization point object)[edit]
a view consisting of a sequence generated by repeatedly incrementing an initial value
(class template) (customization point object)[edit]
a view consisting of a generated sequence by repeatedly producing the same value
(class template) (customization point object)[edit]
a view consisting of the elements obtained by successive application of operator>> on the associated input stream
(class template) (customization point object)[edit]

[edit] Range adaptors

Defined in header <ranges>
Defined in namespace std::ranges
helper base class template for defining a range adaptor closure object
(class template) [edit]
a view that includes all elements of a range
(alias template) (range adaptor object)[edit]
a view of the elements of some other range
(class template) [edit]
a view with unique ownership of some range
(class template) [edit]
a view of a sequence that casts each element to an rvalue
(class template) (range adaptor object)[edit]
a view that consists of the elements of a range that satisfies a predicate
(class template) (range adaptor object)[edit]
a view of a sequence that applies a transformation function to each element
(class template) (range adaptor object)[edit]
a view consisting of the first N elements of another view
(class template) (range adaptor object)[edit]
a view consisting of the initial elements of another view, until the first element on which a predicate returns false
(class template) (range adaptor object)[edit]
a view consisting of elements of another view, skipping the first N elements
(class template) (range adaptor object)[edit]
a view consisting of the elements of another view, skipping the initial subsequence of elements until the first element where the predicate returns false
(class template) (range adaptor object)[edit]
a view consisting of the sequence obtained from flattening a view of ranges
(class template) (range adaptor object)[edit]
a view consisting of the sequence obtained from flattening a view of ranges, with the delimiter in between elements
(class template) (range adaptor object)[edit]
a view over the subranges obtained from splitting another view using a delimiter
(class template) (range adaptor object)[edit]
a view over the subranges obtained from splitting another view using a delimiter
(class template) (range adaptor object)[edit]
a view consisting of concatenation of the adapted views
(class template) (customization point object)[edit]
creates a subrange from an iterator and a count
(customization point object)[edit]
converts a view into a common_range
(class template) (range adaptor object)[edit]
a view that iterates over the elements of another bidirectional view in reverse order
(class template) (range adaptor object)[edit]
converts a view into a constant_range
(class template) (range adaptor object)[edit]
takes a view consisting of tuple-like values and a number N and produces a view of Nth element of each tuple
(class template) (range adaptor object)[edit]
takes a view consisting of pair-like values and produces a view of the first elements of each pair
(class template) (range adaptor object)[edit]
takes a view consisting of pair-like values and produces a view of the second elements of each pair
(class template) (range adaptor object)[edit]
a view that maps each element of adapted sequence to a tuple of both the element's position and its value
(class template) (range adaptor object)[edit]
a view consisting of tuples of references to corresponding elements of the adapted views
(class template) (customization point object)[edit]
a view consisting of results of application of a transformation function to corresponding elements of the adapted views
(class template) (customization point object)[edit]
a view consisting of tuples of references to adjacent elements of the adapted view
(class template) (range adaptor object)[edit]
a view consisting of results of application of a transformation function to adjacent elements of the adapted view
(class template) (range adaptor object)[edit]
a range of views that are N-sized non-overlapping successive chunks of the elements of another view
(class template) (range adaptor object)[edit]
a view whose Mth element is a view over the Mth through (M + N - 1)th elements of another view
(class template) (range adaptor object)[edit]
splits the view into subranges between each pair of adjacent elements for which the given predicate returns false
(class template) (range adaptor object)[edit]
a view consisting of elements of another view, advancing over N elements at a time
(class template) (range adaptor object)[edit]
a view consisting of tuples of results calculated by the n-ary cartesian product of the adapted views
(class template) (customization point object)[edit]

[edit] Range generators

Defined in header <generator>
Defined in namespace std
(C++23)
A view that represents synchronous coroutine generator
(class template) [edit]

[edit] Helper items

[edit] Range adaptor objects

See RangeAdaptorObject (RAO).

[edit] Range adaptor closure objects

See RangeAdaptorClosureObject (RACO).

[edit] Customization point objects

See Customization point object (CPO).

[edit] Assignable wrapper

Some range adaptors wrap their elements or function objects with the copyable-box(until C++23)movable-box(since C++23). The wrapper augments the wrapped object with assignability when needed.

[edit] Non-propagating cache

Some range adaptors are specified in terms of an exposition-only class template non-propagating-cache, which behaves almost like std::optional<T> (see description for differences).

[edit] Conditionally-const type

template< bool Const, class T >
using /*maybe-const*/ = std::conditional_t<Const, const T, T>;
(exposition only*)

The alias template /*maybe-const*/ is a shorthand used to conditionally apply a const qualifier to the type T.

[edit] Integer-like type helper templates

template< /*is-integer-like*/ T >
using /*make-signed-like-t*/<T> = /* see description */;
(1) (exposition only*)
template< /*is-integer-like*/ T >
using /*make-unsigned-like-t*/<T> = /* see description */;
(2) (exposition only*)
template< /*is-integer-like*/ T >

/*make-unsigned-like-t*/<T> /*to-unsigned-like*/( T t )
{
    return static_cast</*make-unsigned-like-t*/<T>>(t);

}
(3) (exposition only*)
1) For an integer-like type T:
  • If T is an integer type, /*make-signed-like-t*/<T> is std::make_signed_t<T>.
  • Otherwise, /*make-signed-like-t*/<T> is a corresponding unspecified signed-integer-like type of the same width as T.
2) For an integer-like type T:
  • If T is an integer type, /*make-unsigned-like-t*/<T> is std::make_unsigned_t<T>.
  • Otherwise, /*make-signed-like-t*/<T> is a corresponding unspecified unsigned-integer-like type of the same width as T.
3) Explicitly converts t to /*make-unsigned-like-t*/<T>.

[edit] Customization point object helpers

template< ranges::input_range R >

constexpr auto& /*possibly-const-range*/(R& r) noexcept
{
    if constexpr (ranges::constant_range<const R> &&
                  !ranges::constant_range<R>)
        return const_cast<const R&>(r);
    else
        return r;

}
(1) (exposition only*)
template< class T >

constexpr auto /*as-const-pointer*/( const T* p ) noexcept
{
    return p;

}
(2) (exposition only*)

Some range access customization point objects are specified in terms of these exposition-only function templates.

1) /*possibly-const-range*/ returns a const-qualified range r if it is a "deep-const" range; otherwise, returns r without any casting.
2) /*as-const-pointer*/ returns a pointer to object of constant type.

[edit] Range adaptor helpers

template< class F, class Tuple >

constexpr auto /*tuple-transform*/( F&& f, Tuple&& tuple )
{
    return std::apply([&]<class... Ts>(Ts&&... args)
    {
        return std::tuple<std::invoke_result_t<F&, Ts>...>
            (std::invoke(f, std::forward<Ts>(args))...);
    }, std::forward<Tuple>(tuple));

}
(1) (exposition only*)
template< class F, class Tuple >

constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple )
{
    std::apply([&]<class... Ts>(Ts&&... args)
    {
        (static_cast<void>(std::invoke(f, std::forward<Ts>(args))), ...);
    }, std::forward<Tuple>(tuple));

}
(2) (exposition only*)
template< class T >

constexpr T& /*as-lvalue*/( T&& t )
{
    return static_cast<T&>(t);

}
(3) (exposition only*)

Some range adaptors are specified in terms of these exposition-only function templates.

1) /*tuple-transform*/ returns a new tuple constructed by applying f to each element of tuple.
2) /*tuple-for-each*/ applies f to each element of tuple and returns nothing.
3) /*as-lvalue*/ forwards rvalue t as lvalue.

[edit] Helper concepts

Following exposition-only concepts are used for several types, but they are not parts of the interface of standard library.

template< class R >

concept /*simple-view*/ =
    ranges::view<R> && ranges::range<const R> &&
    std::same_as<ranges::iterator_t<R>, ranges::iterator_t<const R>> &&

    std::same_as<ranges::sentinel_t<R>, ranges::sentinel_t<const R>>;
(1) (exposition only*)
template< class I >

concept /*has-arrow*/ =
    ranges::input_iterator<I> &&

    (std::is_pointer_v<I> || requires(I i) { i.operator->(); });
(2) (exposition only*)
template< class T, class U >

concept /*different-from*/ =

    !std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
(3) (exposition only*)
template< class R >

concept /*range-with-movable-references*/ =
    ranges::input_range<R> &&
    std::move_constructible<ranges::range_reference_t<R>> &&

    std::move_constructible<ranges::range_rvalue_reference_t<R>>;
(4) (exposition only*)
template< bool C, class... Views >

concept /*all-random-access*/ =
    (ranges::random_access_range

         <std::conditional_t<C, const Views, Views>> && ...);
(5) (exposition only*)
template< bool C, class... Views >

concept /*all-bidirectional*/ =
    (ranges::bidirectional_range

         <std::conditional_t<C, const Views, Views>> && ...);
(6) (exposition only*)
template< bool C, class... Views >

concept /*all-forward*/ =
    (ranges::forward_range

         <std::conditional_t<C, const Views, Views>> && ...);
(7) (exposition only*)

[edit] Notes

Feature-test macro Value Std Feature
__cpp_lib_generator 202207L (C++23) std::generator – synchronous coroutine generator for ranges
__cpp_lib_ranges 201911L (C++20) Ranges library and constrained algorithms
202106L (C++20)
(DR)
Non-default-initializable views
202110L (C++20)
(DR)
Views with ownership
202202L (C++23) ranges::range_adaptor_closure
202207L (C++23) Relaxing range adaptors to allow for move-only types
202211L (C++23) Removing "poison pills" (P2602) overloads in ranges::begin etc
202302L (C++23) Relaxing ranges to allow certain projections
202406L (C++20)
(DR)
Removing the common reference requirement from the indirectly invocable concepts
__cpp_lib_ranges_as_const 202207L (C++23) std::const_iterator, ranges::as_const_view
__cpp_lib_ranges_as_rvalue 202207L (C++23) ranges::as_rvalue_view
__cpp_lib_ranges_cartesian_product 202207L (C++23) ranges::cartesian_product_view
__cpp_lib_ranges_chunk 202202L (C++23) ranges::chunk_view
__cpp_lib_ranges_chunk_by 202202L (C++23) ranges::chunk_by_view
__cpp_lib_ranges_concat 202403L (C++26) ranges::concat_view
__cpp_lib_ranges_enumerate 202302L (C++23) ranges::enumerate_view
__cpp_lib_ranges_join_with 202202L (C++23) ranges::join_with_view
__cpp_lib_ranges_repeat 202207L (C++23) ranges::repeat_view
__cpp_lib_ranges_slide 202202L (C++23) ranges::slide_view
__cpp_lib_ranges_stride 202207L (C++23) ranges::stride_view
__cpp_lib_ranges_to_container 202202L (C++23) ranges::to
__cpp_lib_ranges_zip 202110L (C++23) ranges::zip_view,
ranges::zip_transform_view,
ranges::adjacent_view,
ranges::adjacent_transform_view

[edit] Example

#include <iostream>
#include <ranges>
 
int main()
{
    auto const ints = {0, 1, 2, 3, 4, 5};
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };
 
    // the "pipe" syntax of composing the views:
    for (int i : ints | std::views::filter(even) | std::views::transform(square))
        std::cout << i << ' ';
 
    std::cout << '\n';
 
    // a traditional "functional" composing syntax:
    for (int i : std::views::transform(std::views::filter(ints, even), square))
        std::cout << i << ' ';
}

Output:

0 4 16
0 4 16

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
LWG 3509
(P2281R1)
C++20 it was unclear how range adaptor objects bound trailing arguments they are bound
by value
LWG 3948 C++23 possibly-const-range and as-const-pointer were not declared noexcept declared noexcept

[edit] See also