Namespaces
Variants

std::ranges:: to

From cppreference.net
Ranges library
Range adaptors
Определено в заголовочном файле <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 /*адаптер диапазона замыкания*/ to ( Args && ... args ) ;
(3) (начиная с C++23)
template < template < class ... > class C, class ... Args >
constexpr /*адаптор диапазона-замыкание*/ 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-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) ( только для демонстрации* )
template < class Reference, class C >
constexpr auto /*container-appender*/ ( C & c ) ;
(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 ) ... если все следующие условия true :
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:: for_each ( r, /*container-appender*/ ( c ) ) ;

(до C++26)

if constexpr ( ranges :: approximately_sized_range < R >
&& /*reservable-container*/ < C > )
c. reserve ( static_cast < ranges:: range_size_t < C >> ( ranges :: reserve_hint ( r ) ) ) ;
ranges:: for_each ( r, /*container-appender*/ ( c ) ) ;

(начиная с C++26)

Если R удовлетворяет sized_range (до C++26) approximately_sized_range (начиная с C++26) и C удовлетворяет reservable-container , созданный объект c типа C может зарезервировать память с начальным размером хранилища ranges:: size ( r ) (до C++26) ranges :: reserve_hint ( r ) (начиная с C++26) для предотвращения дополнительных выделений памяти при вставке новых элементов. Каждый элемент r добавляется в c .

Вышеуказанные операции допустимы, если оба следующих условия true :

б) В противном случае возвращаемое выражение эквивалентно:

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 ) ... )

Что позволяет вложенные построения диапазонов внутри диапазона, если ranges:: input_range < ranges:: range_reference_t < C >> равно true .

В противном случае программа является некорректной.
2) Constructs an object of deduced type from the elements of 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 ; // не определен
pointer operator - > ( ) const ; // не определен
/*input-iterator*/ & operator ++ ( ) ; // не определен
/*input-iterator*/ operator ++ ( int ) ; // не определен
bool operator == ( const /*input-iterator*/ & ) const ; // не определен

} ;
( только для демонстрации* )

Пусть /*DEDUCE-EXPR*/ определяется следующим образом:

The call is equivalent to в < decltype ( /*DEDUCE-EXPR*/ ) >
( std:: forward < R > ( r ) , std:: forward < Args > ( args ) ... )
.
3,4) Возвращает обёртку для совершенной пересылки вызова, которая также является RangeAdaptorClosureObject .
5) Является true если удовлетворяет ranges:: sized_range и может быть резервируемым.
6) Является true если один элемент типа Reference может быть добавлен в Container через вызов функции-члена emplace_back , push_back , emplace или insert .
7) Возвращает функциональный объект, при вызове которого происходит эквивалентное добавление одного элемента в контейнер. Возвращаемое выражение эквивалентно:

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 ) ) ;
} ;

8) Используется в определении контейнеров при построении входного диапазона R , тип ссылки диапазона которого должен быть конвертируем в T .

Содержание

Параметры

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

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

1,2) Сконструированный объект, не являющийся представлением.
3,4) Объект замыкания адаптера диапазона неопределенного типа, со следующими свойствами:

ranges::to тип возвращаемого значения

Объекты-члены

Возвращаемый объект ведет себя так, как если бы у него нет целевого объекта, и объект 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.

Исключения

Выбрасывает исключение только в случае, если конструкция не-view объекта выбрасывает исключение.

Примечания

Вставка элементов в контейнер может включать копирование, которое может быть менее эффективным, чем перемещение, поскольку при косвенном вызове создаются ссылки на lvalue. Пользователи могут выбрать использование views:: as_rvalue для адаптации диапазона, чтобы их элементы всегда создавали ссылку на rvalue при косвенном вызове, что подразумевает перемещение.

Скобки являются обязательными при использовании синтаксиса с вертикальной чертой.

auto vec = r | std::ranges::to<std::vector>;   // Ошибка
auto vec = r | std::ranges::to<std::vector>(); // OK
Макрос тестирования возможностей Значение Стандарт Функция
__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 и изменения в std::ranges::to

Пример

Ссылка для предварительного просмотра: Compiler Explorer

#include <boost/container/devector.hpp>
#include <concepts>
#include <initializer_list>
#include <list>
#include <print>
#include <ranges>
#include <regex>
#include <string>
#include <vector>
#ifndef __cpp_lib_format_ranges
#include <format>
#include <sstream>
auto print_aid(const auto& v)
{
    std::ostringstream out;
    out << '[';
    for (int n{}; const auto& e : v)
        out << (n++ ? ", " : "") << e;
    out << ']';
    return out;
}
template<typename T>
struct std::formatter<std::vector<T>, char>
{
    template<class ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx)
    {
        return ctx.begin();
    }
    template<class FmtContext>
    FmtContext::iterator format(auto const& s, FmtContext& ctx) const
    {
        auto out{print_aid(s)};
        return std::ranges::copy(std::move(out).str(), ctx.out()).out;
    }
};
template<typename T>
struct std::formatter<std::list<T>, char>
{
    template<class ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx)
    {
        return ctx.begin();
    }
    template<class FmtContext>
    FmtContext::iterator format(auto const& s, FmtContext& ctx) const
    {
        auto out{print_aid(s)};
        return std::ranges::copy(std::move(out).str(), ctx.out()).out;
    }
};
#endif
int main()
{
    auto vec = std::views::iota(1, 5)
             | std::views::transform([](int v){ return v * 2; })
             | std::ranges::в<std::vector>();
    static_assert(std::same_as<decltype(vec), std::vector<int>>);
    std::println("{}", vec);
    auto list = vec | std::views::take(3) | std::ranges::в<std::list<double>>();
    std::println("{}", list);
}
void ctor_demos()
{
    // 1.a.1) Прямая инициализация
    {
        char array[]{'a', 'b', '\0', 'c'};
        // Тип аргумента конвертируем в тип результирующего значения:
        auto str_to = std::ranges::в<std::string>(array);
        // Эквивалентно
        std::string str(array);
        // Тип результата не является входным диапазоном:
        auto re_to = std::ranges::в<std::regex>(array);
        // Эквивалентно
        std::regex re(array);
    }
    // 1.a.2) конструктор from_range
    {
        auto list = {'a', 'b', '\0', 'c'};
        // Тип аргумента конвертируем в тип результирующего значения:
        auto str_to = std::ranges::в<std::string>(list);
        // Эквивалентно
        // std::string str(std::from_range, list);
        // Тип результата не является входным диапазоном:
        [[maybe_unused]]
        auto pair_to = std::ranges::в<std::pair<std::from_range_t, bool>>(true);
        // Эквивалентно
        std::pair<std::from_range_t, bool> pair(std::from_range, true);
    }
    // 1.a.3) конструктор с парой итераторов
    {
        auto list = {'a', 'b', '\0', 'c'};
        // Тип аргумента конвертируем в тип результирующего значения:
        auto devector_to = std::ranges::в<boost::контейнер::devector<char>>(list);
        // Эквивалентно
        boost::контейнер::devector<char> devector(std::ranges::begin(list),
                                                  std::ranges::end(list));
        // Тип результата не является входным диапазоном:
        std::regex re;
        auto it_to = std::ranges::в<std::cregex_iterator>(list, re);
        // Эквивалентно
        std::cregex_iterator it(std::ranges::begin(list), std::ranges::end(list), re);
    }
}

Вывод:

[2, 4, 6, 8]
[2, 4, 6]
**Примечание:** В данном случае переводить нечего, так как: 1. Весь текст внутри тегов `
` содержит только числовые данные и синтаксические символы
2. HTML-теги и атрибуты сохранены без изменений
3. Отсутствует текстовый контент, подлежащий переводу

Отчёты о дефектах

Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
LWG 3984 C++23 вложенная ветка конструктора ranges::to приводила к
некорректной программе, если R& не моделирует viewable_range
сделана корректной
LWG 4016 C++23 ветка вставки в контейнер
ranges::to использовала итераторы вставки
заменена на прямое добавление
элементов в контейнер

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 26.5.7 Преобразования диапазонов [range.utility.conv]