home | help
std::ranges::to(3)	       C++ Standard Libary	      std::ranges::to(3)

NAME
     std::ranges::to - std::ranges::to

Synopsis
	Defined in header <ranges>
	template< class C, ranges::input_range R, class... Args >

	    requires   (!ranges::view<C>)				     (1)
     (since C++23)

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

	    requires   (!ranges::view<C>)				     (3)
     (since C++23)

	constexpr /*range adaptor closure*/ to( Args&&... args );
	template< template< class... > class C, class...  Args	>	     (4)
     (since C++23)
	constexpr /*range adaptor closure*/ to( Args&&... args );
	Helper templates
	template< class Container >

	constexpr bool /*reservable-container*/ =
	    ranges::sized_range<Container> &&
	    requires	(Container&    c,   ranges::range_size_t<Container>   n)
     (exposition
	    {								     (5)
     only*)
		c.reserve(n);
		{ c.capacity() } -> std::same_as<decltype(n)>;
		{ c.max_size() } -> std::same_as<decltype(n)>;

	    };
	template< class Container, class Reference >

	constexpr bool /*container-appendable*/ = requires (Container& c,
	Reference&& ref)
	{
	    requires (requires {
	c.emplace_back(std::forward<Reference>(ref));		}	      ||
     (exposition
		      requires	{					     (6)
     only*)
	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)); });

	};
	template< class Reference, class C >

	constexpr auto /*container-appender*/( C& c )
	{
	    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	       {
     (exposition
	c.push_back(std::declval<Reference>());  })			     (7)
     only*)
		    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));
	    };

	}
	template< class R, class T >

	concept  /*container-compatible-range*/  =			     (8)
     (exposition
	    ranges::input_range<R>					      &&
     only*)

	    std::convertible_to<ranges::range_reference_t<R>, T>;

	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, 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  follow-
     ing:
	a) If C does not satisfy input_range or
	std::convertible_to<ranges::range_reference_t<R>,
     ranges::range_value_t<C>> is true:
	1) Constructing a non-view 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 object as if direct-initializing
     (but not
	direct-list-initializing) an object of type  C	from  additional  disam-
     biguation 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 object as if direct-initializing
     (but not
	direct-list-initializing) an object of type C from the iterator-sentinel
     pair
	(ranges::begin(r) as an iterator and ranges::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  arguments  std::forward<Args>(args)...
     if all of the
	conditions below are true:
	  * ranges::common_range<R>
	  * If std::iterator_traits<ranges::iterator_t<R>>::iterator_category is
     valid and
	    denotes  a	type  that satisfies std::derived_from<std::input_itera-
     tor_tag>
	  *   std::constructible_from<C,   ranges::iterator_t<R>,   ranges::sen-
     tinel_t<R>,
	    Args...>
	4) Otherwise, constructing a non-view range object as if direct-initial-
     izing (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(static_cast<ranges::range_size_t<C>>(ranges::size(r)));
	ranges::for_each(r, /*container-appender*/(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  ini-
     tial storage
	size  ranges::size(r) to prevent additional allocations during inserting
     new
	elements. Each element of r is appended to c. The operations  above  are
     valid if both
	of the conditions below are true:

	  * std::constructible_from<C, Args...>
	  * /*container-appendable*/<C, ranges::range_reference_t<R>>
	b) Otherwise, the return expression is equivalent to:

	to<C>(ranges::ref_view(r) | views::transform([](auto&& elem)
	{
	    return		   to<ranges::range_value_t<C>>(std::forward<de-
     cltype(elem)>(elem));
	}), std::forward<Args>(args)...)
	Which allows nested range constructions within the range if
	ranges::input_range<ranges::range_reference_t<C>> 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*/

	{
	    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 							  (expo-
     sition only*)
	    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:

	  * C(std::declval<R>(), std::declval<Args>()...), if that expression is
     valid.
	  *   Otherwise,    C(std::from_range,	  std::declval<R>(),	std::de-
     clval<Args>()...), if
	    that expression is valid.
	  * Otherwise, C(std::declval</*input-iterator*/>(),
	    std::declval</*input-iterator*/>(),   std::declval<Args>()...),   if
     that expression
	    is valid.
	  * Otherwise, the program is ill-formed.
	The  call  is  equivalent   to	 to<decltype(/*DEDUCE-EXPR*/)>(std::for-
     ward<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*/<Con-
     tainer> is true
	if it satisfies ranges::sized_range and is eligible to be reservable.
	6) The exposition-only variable  template  /*container-appendable*/<Con-
     tainer,
	Reference>  is	true if one element of type Reference can be appended to
     Container
	through a member function call emplace_back, push_back, emplace  or  in-
     sert.
	7)  The exposition-only function template /*container-appender*/ returns
     a function
	object where a call to the returned function object is expression-equiv-
     alent to
	appending one element to a container.
	8) The exposition-only concept /*container-compatible-range*/ is used in
     the
	definition of containers in constructing an input range  R  whose  range
     reference type
	must be convertible to T.

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

Type requirements
	-
	C must be cv-unqualified class type (1,3)

Return value
	1,2) A constructed non-view object.
	3,4)  A  range adaptor closure object of unspecified type, with the fol-
     lowing
	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::for-
     ward<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 con-
     structors perform
	a memberwise copy/move. It is CopyConstructible if all of its member ob-
     jects
	(specified above) are CopyConstructible, and is MoveConstructible other-
     wise.

Member function operator()
	Given an object G obtained from an earlier call to range::to</* see  be-
     low
	*/>(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.

Exceptions
	Only throws if construction of a non-view object throws.

Notes
	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 use views::as_rvalue to adapt the range in or-
     der 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>;   // error
      auto 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

Example
	A preview link: Compiler Explorer

     // Run this code

      #include <concepts>
      #include <list>
      #include <print>
      #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::println("{}", vec);

	  auto lst = vec | std::views::take(3) |  std::ranges::to<std::list<dou-
     ble>>();
	  std::println("{}", lst);
      }

Output:
      [2, 4, 6, 8]
      [2, 4, 6]

References
	  * C++23 standard (ISO/IEC 14882:2023):

	  * 26.5.7 Range conversions [range.utility.conv]

	Defect reports

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

	   DR	 Applied to	    Behavior as  published		 Correct
     behavior
			    the nested construction branch of
	LWG  3984  C++23       ranges::to			      made well-
     formed
			    resulted to program ill-formed if R&
			    does not model viewable_range
			    the container insertion branch of	   replaced with
     direct
	LWG 4016 C++23	    ranges::to involved use of		   appending
			    insert iterators			    of	elements
     to container

http://cppreference.com 	   2024.06.10		      std::ranges::to(3)

home | help