Namespaces
Variants
Views
Actions

std::ranges::to

From cppreference.com
< cpp‎ | ranges
 
 
Ranges library
Range access
Range conversions
to
(C++23)
Range primitives



Dangling iterator handling
Range concepts
Views

Factories




Adaptors
Range adaptor objects
Range adaptor closure objects
Helper items
 
Defined in header <ranges>
template< class C, ranges::input_range R, class... Args >

  requires (!ranges::view<C>)

constexpr C to( R&& r, Args&&... args );
(1) (since C++23)
template< template< class... > class C, ranges::input_range R, class... Args >
constexpr auto to( R&& r, Args&&... args );
(2) (since C++23)
template< class C, class... Args >

  requires (!ranges::view<C>)

constexpr /*range adaptor closure*/ to( Args&&... args );
(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 >

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) (since C++23)
template< class Container, class Reference >

constexpr bool /*container-insertable*/ = requires (Container& c, Reference&& ref) {
  requires (requires { c.push_back(std::forward<Reference>(ref)); } ||
            requires { c.insert(c.end(), std::forward<Reference>(ref)); });

};
(6) (since C++23)
template< class Reference, class C >

constexpr auto /*container-inserter*/(C& c) {
  if constexpr (requires { c.push_back(std::declval<Reference>()); })
    return std::back_inserter(c);
  else
    return std::inserter(c, c.end());

}
(7) (since C++23)
template< class R, class T >

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

  std::convertible_to<ranges::range_reference_t<R>, T>;
(8) (since C++23)

The overloads of the range conversion function construct a new non-view range object from a source range as its first argument by calling a constructor taking a range, a std::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.

1) Constructs an object of type C from the elements of r in the following:
1) Constructing a non-view range object as if direct-initializing (but not direct-list-initializing) an object of type C from the source range std::forward<R>(r) and the rest of the functional arguments std::forward<Args>(args)... if std::constructible_from<C, R, Args...> is true.
2) Otherwise, constructing a non-view range object as if direct-initializing (but not direct-list-initializing) an object of type C from additional disambiguation tag std::from_range, the source range std::forward<R>(r) and the rest of the functional arguments std::forward<Args>(args)... if std::constructible_from<C, std::from_range_t, R, Args...> is true.
3) Otherwise, constructing a non-view range object as if direct-initializing (but not direct-list-initializing) an object of type C from the iterator-sentinel pair (ranges::begin(r) as iterator and ranges::end(r) as sentinel where iterator and sentinel has the same type. In other words, the source range must be a common range), and the rest of function arguments std::forward<Args>(args)... if all of the conditions below are true:
4) Otherwise, constructing a non-view range object as if direct-initializing (but not direct-list-initializing) an object of type C from the rest of the function arguments std::forward<Args>(args)... with the following equivalent call below after the construction:
if constexpr (ranges::sized_range<R> && /*reservable-container*/<C>)

  c.reserve(ranges::size(r));

ranges::copy(r, /*container-inserter*/<ranges::range_reference_t<R>>(c));

If the R satisfies sized_range and C satisfies /*reservable-container*/, the constructed object c of type C is able to reserve storage with the initial storage size ranges::size(r) to prevent additional allocations during inserting new elements. Each range reference element of r is back inserted to c through ranges::copy with back inserter adaptor. The operations above are valid if both of the conditions below are true:

b) Otherwise, the return expression is equivalent to:
to<C>(r | views::transform([](auto&& elem) {

  return to<ranges::range_value_t<R>>(std::forward<decltype(elem)>(elem));

}, std::forward<Args>(args)...)

Which allows nested range constructions within the range if ranges::input_range<ranges::range_reference_t<R>> is true.

Otherwise, the program is ill-formed.
2) Constructs an object of deduced type from the elements of r.

Let /*input-iterator*/ be an exposition only type that satisfies LegacyInputIterator:

struct /*input-iterator*/ {                         // exposition only

  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

};

Let /*DEDUCE-EXPR*/ be defined as follows:

The call is equivalent to to<decltype(/*DEDUCE-EXPR*/)>(std::forward<R>(r), std::forward<Args>(args)...).
3-4) Returns a perfect forwarding call wrapper that is also a RangeAdaptorClosureObject.
5) The exposition-only variable template /*reservable-container*/<Container> is true if it satisfies ranges::sized_range and is eligible to be reservable.
6) The exposition-only variable template /*container-insertable*/<Container, Reference> is true if Container is back insertable by a member function call push_back or insert.
7) The exposition-only function template /*container-inserter*/ returns an output iterator of type std::back_insert_iterator if member function push_back is available, otherwise the type is std::insert_iterator.
8) The exposition-only concept /*container-compatible-range*/ is used in the definition of containers in constructing an input range R and its range reference type must be convertible to T.

Contents

[edit] Parameters

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.

[edit] Return value

1-2) a constructed non-view range object
3-4) a range adaptor closure object of unspecified type, with the following properties:

ranges::to return type

The return type is derived from ranges::range_adaptor_closure</*return-type*/>.

Member objects

The returned object behaves as if it has no target object, and an std::tuple object tup constructed with std::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.

Constructors

The return type of ranges::to (3-4) behaves as if its copy/move constructors perform a memberwise copy/move. It is CopyConstructible if all of its member objects (specified above) are CopyConstructible, and is MoveConstructible otherwise.

Member function operator()

Given an object G obtained from an earlier call to range::to</* see below */>(args...), when a glvalue g designating G is invoked in a function call expression g(r), an invocation of the stored object takes place, as if by

  • ranges::to</* see below */>(r, std::get<Ns>(g.tup)...), where
  • r is a source range object that must satisfy input_range
  • Ns is an integer pack 0, 1, ..., (sizeof...(Args) - 1)
  • g is an lvalue in the call expression if it is an lvalue in the call expression, and is an rvalue otherwise. Thus std::move(g)(r) can move the bound arguments into the call, where g(r) would copy.
  • The specified template argument is (3) C or (4) the deduced type from a class template C that must not satisfy view.

The program is ill-formed if g has volatile-qualified type.

[edit] Exceptions

Only throws if construction of a range object throws.

[edit] Notes

The insertion of elements into the container may involve copy which can be more inefficient than move because lvalue references are produced during the indirection call. Users can opt-in to use views::as_rvalue to adapt the range in order for their elements to always produce an rvalue reference during the indirection call which implies move.

Feature-test macro Value Std Comment
__cpp_lib_ranges_to_container 202202L (C++23) std::ranges::to

[edit] Example

A link to test Compiler Explorer msvc.latest

#include <algorithm>
#include <concepts>
#include <iostream>
#include <ranges>
#include <vector>
 
int main()
{
    auto vec = std::views::iota(1, 5)
             | std::views::transform([](auto const v){ return v * 2; })
             | std::ranges::to<std::vector>();
 
    static_assert(std::same_as<decltype(vec), std::vector<int>>);
 
    std::ranges::for_each(vec, [](auto const v){ std::cout << v << ' '; });
}

Output:

2 4 6 8