std::ranges::to
| Défini dans l'en-tête <ranges>
|
||
template< class C, ranges::input_range R, class... Args >
requires (!ranges::view<C>)
constexpr C to( R&& r, Args&&... args );
|
(1) | (depuis C++23) |
template< template< class... > class C,
ranges::input_range R, class... Args >
constexpr auto to( R&& r, Args&&... args );
|
(2) | (depuis C++23) |
template< class C, class... Args >
requires (!ranges::view<C>)
constexpr /*range adaptor closure*/ to( Args&&... args );
|
(3) | (depuis C++23) |
template< template< class... > class C, class... Args >
constexpr /*range adaptor closure*/ to( Args&&... args );
|
(4) | (depuis C++23) |
| Patrons d'aide |
||
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) | (uniquement d'exposition*) |
template< class Container, class Reference >
constexpr bool /*container-appendable*/ =
requires (Container& c, Reference&& ref)
{
requires
(
requires { c.emplace_back(std::forward<Reference>(ref)); } ||
requires { 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)); }
);
};
|
(6) | (uniquement d'exposition*) |
template< class Reference, class C >
constexpr auto /*container-appender*/( C& c );
|
(7) | (uniquement d'exposition*) |
template< class R, class T >
concept /*container-compatible-range*/ =
ranges::input_range<R> &&
std::convertible_to<ranges::range_reference_t<R>, T>;
|
(8) | (uniquement d'exposition*) |
Les surcharges de la fonction de conversion de plage construisent un nouvel objet non-vue à partir d'une plage source comme premier argument en appelant un constructeur prenant une plage, un std::from_range_t constructeur de plage étiquetée, un constructeur prenant une paire itérateur-sentinelle, ou en insérant par l'arrière chaque élément de la plage source dans l'objet construit avec les arguments.
C à partir des éléments de r comme suit :C ne satisfait pas input_range ou si std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> est true :C à partir de la plage source std::forward<R>(r) et du reste des arguments fonctionnels std::forward<Args>(args)... si std::constructible_from<C, R, Args...> est true.C à partir de la balise de désambiguïsation supplémentaire std::from_range, de la plage source std::forward<R>(r) et du reste des arguments fonctionnels std::forward<Args>(args)... si std::constructible_from<C, std::from_range_t, R, Args...> est true.C à partir de la paire itérateur-sentinelle (ranges::begin(r) comme itérateur et ranges::end(r) comme sentinelle, où l'itérateur et la sentinelle ont le même type. En d'autres termes, la plage source doit être une plage commune), et du reste des arguments de fonction std::forward<Args>(args)... si toutes les conditions ci-dessous sont true:
ranges::common_range<R>- Si
std::iterator_traits<ranges::iterator_t<R>>::iterator_categoryest valide et désigne un type qui satisfaitstd::derived_from<std::input_iterator_tag> std::constructible_from<C, ranges::iterator_t<R>, ranges::sentinel_t<R>, Args...>
C à partir du reste des arguments de fonction std::forward<Args>(args)... avec l'appel équivalent suivant après la construction :
|
|
(jusqu'à C++26) |
|
|
(depuis C++26) |
Si le
R satisfait sized_range(jusqu'à C++26)approximately_sized_range(depuis C++26) et C satisfait reservable-container, l'objet construit c de type C est capable de réserver du stockage avec la taille de stockage initiale ranges::size(r)(jusqu'à C++26)ranges::reserve_hint(r)(depuis C++26) pour éviter des allocations supplémentaires lors de l'insertion de nouveaux éléments. Chaque élément de r est ajouté à c.
Les opérations ci-dessus sont valides si les deux conditions ci-dessous sont true :
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)...)
Ce qui permet des constructions de plages imbriquées dans la plage si ranges::input_range<ranges::range_reference_t<C>> est true.
r.
Soit /*input-iterator*/ un type d'exposition uniquement qui satisfait 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
pointer operator->() const; // not defined
/*input-iterator*/& operator++(); // not defined
/*input-iterator*/ operator++(int); // not defined
bool operator==(const /*input-iterator*/&) const; // not defined
};
|
(uniquement d'exposition*) | |
Soit /*DEDUCE-EXPR*/ défini comme suit :
C(std::declval<R>(), std::declval<Args>()...), si cette expression est valide.- Sinon,
C(std::from_range, std::declval<R>(),std::declval<Args>()...), si cette expression est valide.
- Sinon,
C(std::declval</*input-iterator*/>(),std::declval</*input-iterator*/>(),std::declval<Args>()...), si cette expression est valide.
- Sinon, le programme est mal formé.
L'appel est équivalent à
to<decltype(/*DEDUCE-EXPR*/)> (std::forward<R>(r), std::forward<Args>(args)...).true s'il satisfait ranges::sized_range et est éligible pour être réservable.true si un élément de type Reference peut être ajouté à Container via un appel de fonction membre emplace_back, push_back, emplace ou insert.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 dont le type de référence de plage doit être convertible en T.Paramètres
| r | - | un objet de plage source |
| args | - | liste des arguments pour ( 1,2 ) construire une plage ou ( 3,4 ) lier aux derniers paramètres de l'objet de fermeture d'adaptateur de plage |
| Exigences de type | ||
-
C
doit être un type de classe non qualifié cv
(
1,3
)
|
||
Valeur de retour
ranges::to type de retour
Objets membres
L'objet retourné se comporte comme s'il n'avait pas d'objet cible, et un objet std::tuple tup construit avec std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) , sauf que le comportement d'affectation de l'objet retourné n'est pas spécifié et les noms sont uniquement à titre d'exposition.
Constructeurs
Le type de retour de
ranges::to
(
3,4
)
se comporte comme si ses constructeurs de copie/déplacement effectuaient une copie/déplacement membre par membre. Il est
CopyConstructible
si tous ses objets membres (spécifiés ci-dessus) sont
CopyConstructible
, et est
MoveConstructible
sinon.
Fonction membre
operator()
Étant donné un objet
G
obtenu d'un appel antérieur à
range
::
to
<
/* see below */
>
(
args...
)
, lorsqu'une glvalue
g
désignant
G
est invoquée dans une expression d'appel de fonction
g
(
r
)
, un appel de l'objet stocké a lieu, comme par
- ranges :: to < /* see below */ > ( r, std :: get < Ns > ( g. tup ) ... ) , où
-
-
r
est un objet plage source qui doit satisfaire
input_range. - Ns est un pack d'entiers 0 , 1 , ..., ( sizeof... ( Args ) - 1 ) .
- g est une lvalue dans l'expression d'appel si c'est une lvalue dans l'expression d'appel, et est une rvalue sinon. Ainsi std :: move ( g ) ( r ) peut déplacer les arguments liés dans l'appel, où g ( r ) copierait.
-
L'argument template spécifié est
(
3
)
Cou ( 4 ) le type déduit d'un template de classeCqui ne doit pas satisfaireview.
-
r
est un objet plage source qui doit satisfaire
Le programme est mal formé si g a un type qualifié volatile.
Exceptions
Ne lance que si la construction d'un objet non-vue lève une exception.
Notes
L'insertion d'éléments dans le conteneur peut impliquer une copie qui peut être moins efficace que le déplacement car des références lvalue sont produites lors de l'appel d'indirection. Les utilisateurs peuvent opter pour utiliser views:: as_rvalue pour adapter la plage afin que leurs éléments produisent toujours une référence rvalue lors de l'appel d'indirection, ce qui implique un déplacement.
Les parenthèses sont obligatoires lors de l'utilisation de la syntaxe de pipe.
auto vec = r | std::ranges::to<std::vector>; // Erreur auto vec = r | std::ranges::to<std::vector>(); // Correct
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__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
, et
modifications
de
std::ranges::to
|
Exemple
Un lien d'aperçu : Compiler Explorer
#include <boost/container/devector.hpp>
#include <concepts>
#include <initializer_list>
#include <list>
#include <print>
#include <ranges>
#include <regex>
#include <string>
#include <vector>
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("1) {}", vec);
auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
std::println("2) {}", 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);
}
}
Sortie :
1) [2, 4, 6, 8]
2) [2, 4, 6]
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Applicable à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| LWG 3984 | C++23 |
la branche de construction imbriquée de
ranges::to
rendait le programme
mal formé si
R&
ne modélise pas
viewable_range
|
rendu bien formé |
| LWG 4016 | C++23 |
la branche d'insertion de conteneur de
ranges::to
impliquait l'utilisation d'itérateurs d'insertion
|
remplacée par l'ajout direct
d'éléments au conteneur |
Références
- Norme C++23 (ISO/CEI 14882:2024) :
-
- 26.5.7 Conversions de plages [range.utility.conv]