std::ranges::to
Определено в заголовке <ranges> | ||
|---|---|---|
template< class C, ranges::input_range R, class... Args >
requires (!ranges::view<C>)
constexpr C to( R&& r, Args&&... args ); | (1) | (с C++23) |
template< template< class... > class C, ranges::input_range R, class... Args > constexpr auto to( R&& r, Args&&... args ); | (2) | (с C++23) |
template< class C, class... Args >
requires (!ranges::view<C>)
constexpr /*range adaptor closure*/ to( Args&&... args ); | (3) | (с C++23) |
template< template< class... > class C, class... Args > constexpr /*range adaptor closure*/ to( Args&&... args ); | (4) | (с C++23) |
| Вспомогательные шаблоны | ||
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) | (только для иллюстрации*) |
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) | (только для иллюстрации*) |
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) | (только для иллюстрации*) |
template< class R, class T >
concept /*container-compatible-range*/ =
ranges::input_range<R> &&
std::convertible_to<ranges::range_reference_t<R>, T>;
| (8) | (только для иллюстрации*) |
Перегрузки функции преобразования диапазона создают новый объект без представления из исходного диапазона в качестве первого аргумента, вызывая конструктор, принимающий диапазон, конструктор, принимающий метку диапазона std::from_range_t, конструктор, принимающий пару итератор-конечный итератор, или путём добавления каждого элемента исходного диапазона в создаваемый объект.
C из элементов r следующим образом:C не удовлетворяет input_range или std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> равно true: C из исходного диапазона std::forward<R>(r) и остальных функциональных аргументов std::forward<Args>(args)..., если std::constructible_from<C, R, Args...> равно true.C из дополнительной разделяющей метки std::from_range, исходного диапазона std::forward<R>(r) и остальных функциональных аргументов std::forward<Args>(args)..., если std::constructible_from<C, std::from_range_t, R, Args...> равно true.C из пары итератор-конечный итератор (ranges::begin(r) в качестве итератора и ranges::end(r) в качестве конечного итератора, где итератор и конечный итератор имеют один тип. Другими словами, исходный диапазон должен быть общим диапазоном), и остальных функциональных аргументов std::forward<Args>(args)..., если все условия ниже выполняются: -
ranges::common_range<R> - Если
std::iterator_traits<ranges::iterator_t<R>>::iterator_categoryявляется корректным и обозначает тип, который удовлетворяетstd::derived_from<std::input_iterator_tag> -
std::constructible_from<C, ranges::iterator_t<R>, ranges::sentinel_t<R>, Args...>
C из остальных функциональных аргументов std::forward<Args>(args)... с последующим вызовом эквивалентного кода ниже после создания: if constexpr (ranges::sized_range<R> && /*reservable-container*/<C>)
c.reserve(static_cast<ranges::range_size_t<C>>(ranges::size(r)));
ranges::copy(r, /*container-inserter*/<ranges::range_reference_t<R>>(c));
Если R удовлетворяет sized_range и C удовлетворяет /*reservable-container*/, созданный объект c типа C способен зарезервировать память с начальным размером ranges::size(r) для предотвращения дополнительных выделений при добавлении новых элементов. Каждый элемент диапазона r добавляется в конец c с помощью адаптера back inserter ranges::copy. Данные операции допустимы, если оба следующих условия выполняются:
-
std::constructible_from<C, Args...> -
/*container-insertable*/<C, ranges::range_reference_t<R>>
to<C>(r | views::transform([](auto&& elem)
{
return to<ranges::range_value_t<C>>(std::forward<decltype(elem)>(elem));
}), std::forward<Args>(args)...)
Что позволяет встраивать вложенные диапазоны в диапазон, если ranges::input_range<ranges::range_reference_t<C>> равно true. В противном случае, программа некорректна.
r. Пусть /*input-iterator*/ — тип только для иллюстрации, который удовлетворяет 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
};
| (только для иллюстрации*) |
Пусть /*DEDUCE-EXPR*/ определяется следующим образом:
-
C(std::declval<R>(), std::declval<Args>()...), если это выражение корректно. - В противном случае,
C(std::from_range, std::declval<R>(), std::declval<Args>()...), если это выражение корректно. - В противном случае,
C(std::declval</*input-iterator*/>(), std::declval</*input-iterator*/>(), std::declval<Args>()...), если это выражение корректно. - В противном случае, программа некорректна.
to<decltype(/*DEDUCE-EXPR*/)>(std::forward<R>(r), std::forward<Args>(args)...). /*reservable-container*/<Container> равна true, если она удовлетворяет ranges::sized_range и может быть резервируемой./*container-insertable*/<Container, Reference> равна true, если Container может быть добавлена в конец с помощью вызова члена push_back или insert./*container-inserter*/ возвращает итератор вывода типа std::back_insert_iterator, если доступна функция-член push_back, в противном случае тип std::insert_iterator.
/*container-compatible-range*/ используется в определении контейнеров при создании входного диапазона R, а тип ссылки на его диапазон должен быть преобразуем в T.Параметры
| r | - | объект исходного диапазона |
| args | - | список аргументов для (1,2) построения диапазона или (3,4) привязки к последним параметрам объекта-замыкания адаптера диапазона |
Возвращаемое значение
Тип возвращаемого значения ranges::to
Тип возвращаемого значения выводится из ranges::range_adaptor_closure</*return-type*/>.
Члены-объекты
Возвращаемый объект ведет себя так, как будто у него нет целевого объекта, и объект std::tuple tup создается с std::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...), за исключением того, что поведение присваивания возвращаемого объекта не определено, а имена — только для иллюстрации.
Конструкторы
Тип возвращаемого значения ranges::to (3-4) ведет себя так, как будто его конструкторы копирования/перемещения выполняют поэлементное копирование/перемещение. Он является CopyConstructible, если все его члены-объекты (указанные выше) являются CopyConstructible, и MoveConstructible в противном случае.
Функция-член operator()
Для объекта G, полученного из предыдущего вызова range::to</* see below */>(args...), при вызове glvalue g, обозначающего G, в выражении вызова функции g(r), происходит вызов сохраненного объекта, как если бы
-
ranges::to</* see below */>(r, std::get<Ns>(g.tup)...), где -
r— объект исходного диапазона, который должен удовлетворятьinput_range. -
Ns— целочисленный пакет0, 1, ..., (sizeof...(Args) - 1). -
g— lvalue в выражении вызова, если оно lvalue, и rvalue в противном случае. Таким образом,std::move(g)(r)может переместить привязанные аргументы в вызов, гдеg(r)скопировал бы их. - Указанный шаблонный аргумент — (3)
Cили (4) тип, выведенный из шаблона классаC, который не должен удовлетворятьview.
Программа некорректна, если g имеет тип с квалификатором volatile.
Исключения
Бросает исключение только в случае возникновения исключения при создании объекта без представления.
Примечания
Добавление элементов в контейнер может включать копирование, что может быть менее эффективным, чем перемещение, потому что во время косвенного вызова генерируются lvalue ссылки. Пользователи могут включить использование views::as_rvalue для адаптации диапазона, чтобы его элементы всегда генерировали ссылку rvalue во время косвенного вызова, что подразумевает перемещение.
Скобки обязательны при использовании синтаксиса конвейера.
auto vec = r | std::ranges::to<std::vector>; // error auto vec = r | std::ranges::to<std::vector>(); // OK
| Тест функции макрос | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_lib_ranges_to_container | 202202L | (C++23) |
std::ranges::to |
Пример
Ссылка на предварительный просмотр: Компилятор Explorer
#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<double>>();
std::println("{}", lst);
}Вывод:
[2, 4, 6, 8] [2, 4, 6]
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2023):
- 26.5.7 Преобразования диапазонов [range.utility.conv]
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/ranges/to