Spec-Zone.ru › C++

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, конструктор, принимающий пару итератор-конечный итератор, или путём добавления каждого элемента исходного диапазона в создаваемый объект.

1) Создаёт объект типа C из элементов r следующим образом:
a) Если C не удовлетворяет input_range или std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> равно true:
1) Создаёт объект без представления так, как если бы происходило прямое инициализирование (но не прямое списковое инициализирование) объекта типа C из исходного диапазона std::forward<R>(r) и остальных функциональных аргументов std::forward<Args>(args)..., если std::constructible_from<C, R, Args...> равно true.
2) В противном случае, создаёт объект без представления так, как если бы происходило прямое инициализирование (но не прямое списковое инициализирование) объекта типа C из дополнительной разделяющей метки std::from_range, исходного диапазона std::forward<R>(r) и остальных функциональных аргументов std::forward<Args>(args)..., если std::constructible_from<C, std::from_range_t, R, Args...> равно true.
3) В противном случае, создаёт объект без представления так, как если бы происходило прямое инициализирование (но не прямое списковое инициализирование) объекта типа 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...>
4) В противном случае, создаёт объект без представления диапазона так, как если бы происходило прямое инициализирование (но не прямое списковое инициализирование) объекта типа 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>>
b) В противном случае, выражение возврата эквивалентно:

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. В противном случае, программа некорректна.

2) Создаёт объект выведенного типа из элементов 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)...).
3,4) Возвращает обёртку вызова идеальной передачи, которая также является RangeAdaptorClosureObject.
5) Шаблон-переменная только для иллюстрации /*reservable-container*/<Container> равна true, если она удовлетворяет ranges::sized_range и может быть резервируемой.
6) Шаблон-переменная только для иллюстрации /*container-insertable*/<Container, Reference> равна true, если Container может быть добавлена в конец с помощью вызова члена push_back или insert.
7) Шаблон-функция только для иллюстрации /*container-inserter*/ возвращает итератор вывода типа std::back_insert_iterator, если доступна функция-член push_back, в противном случае тип std::insert_iterator.
8) Концепция только для иллюстрации /*container-compatible-range*/ используется в определении контейнеров при создании входного диапазона R, а тип ссылки на его диапазон должен быть преобразуем в T.

Параметры

r - объект исходного диапазона
args - список аргументов для (1,2) построения диапазона или (3,4) привязки к последним параметрам объекта-замыкания адаптера диапазона

Возвращаемое значение

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API