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 /*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-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) 通过以下方式从 r 的元素构造一个类型为 C 的对象:
1) 如同以直接初始化(但不包括直接列表初始化)方式,从源范围 std:: forward < R > ( r ) 和其余函数实参 std:: forward < Args > ( args ) ... 构造一个非视图对象,当且仅当 std:: constructible_from < C, R, Args... > true
2) 否则,如同使用附加消歧标签 std:: from_range 、源范围 std:: forward < R > ( r ) 及其他函数参数 std:: forward < Args > ( args ) ... 对类型 C 的对象进行 直接初始化 (但不包括直接列表初始化)的方式构造非视图对象,前提是 std:: constructible_from < C, std:: from_range_t , R, Args... > true
3) 否则,如同使用迭代器-哨位对(以 ranges:: begin ( r ) 作为迭代器、 ranges:: end ( r ) 作为哨位,其中迭代器与哨位具有相同类型。换言之,源范围必须是公共范围)以及其余函数参数 std:: forward < Args > ( args ) ... 直接初始化 (但不包括直接列表初始化)类型 C 的对象那样构造非视图对象,当以下所有条件均为 true 时:
4) 否则,如同通过函数剩余参数 std:: forward < Args > ( args ) ... 对类型 C 的对象进行 直接初始化 (但不包括直接列表初始化)那样构造一个非视图范围对象,并在构造后执行以下等效调用:

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 时,上述操作有效:

b) 否则,返回表达式等价于:

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) 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*/ 按如下方式定义:

该调用等价于 to < decltype ( /*DEDUCE-EXPR*/ ) >
( std:: forward < R > ( r ) , std:: forward < Args > ( args ) ... )
3,4) 返回一个完美转发调用包装器,该包装器同时也是一个 RangeAdaptorClosureObject
5) 若满足 ranges:: sized_range 且符合可预留条件,则为 true
6) 当类型为 true 时,表示可以通过成员函数调用 emplace_back push_back emplace insert Reference 类型的元素追加到 Container 中。
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 返回类型

成员对象

返回的对象表现为没有目标对象,并具有一个用 tup 构造的 std::tuple 对象 std:: tuple < std:: decay_t < Args > ... > ( std:: forward < Args > ( args ) ... ) ,但返回对象的赋值行为未指定且名称仅用于说明目的。

构造函数

ranges::to ( 3,4 ) 的返回类型表现为其拷贝/移动构造函数执行成员级的拷贝/移动。如果其所有成员对象(如上所述)均满足 可拷贝构造 ,则该类型为 可拷贝构造 ,否则为 可移动构造

成员函数 operator()

给定从先前调用 range :: to < /* see below */ > ( args... ) 获得的对象 G ,当指代 G 的泛左值 g 在函数调用表达式 g ( r ) 中被调用时,会执行存储对象的调用,如同通过

  • ranges :: to < /* see below */ > ( r, std :: get < Ns > ( g. tup ) ... ) ,其中
  • r 是必须满足 input_range 的源范围对象。
  • Ns 是整数包 0 , 1 , ..., ( sizeof... ( Args ) - 1 )
  • g 在调用表达式中是左值(如果它在调用表达式中是左值),否则是右值。因此 std :: move ( g ) ( r ) 可以将绑定的参数移动到调用中,而 g ( r ) 会进行拷贝。
  • 指定的模板实参是 ( 3 ) C ( 4 ) 从类模板 C 推导出的类型,且该类型不得满足 view

如果 g 具有 volatile 限定类型,则程序非良构。

异常

仅当非视图对象的构造抛出异常时才会抛出。

注释

向容器中插入元素可能涉及拷贝操作,由于间接调用过程中会产生左值引用,这比移动操作的效率更低。用户可以选择使用 views:: as_rvalue 来适配范围,使得其元素在间接调用过程中始终产生右值引用,这意味着将执行移动操作。

使用管道语法时圆括号是必需的。

auto vec = r | std::ranges::to<std::vector>;   // 错误
auto vec = r | std::ranges::to<std::vector>(); // 正确
功能测试 标准 功能特性
__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::to<std::vector>();
    static_assert(std::same_as<decltype(vec), std::vector<int>>);
    std::println("{}", vec);
    auto list = vec | std::views::take(3) | std::ranges::to<std::list<double>>();
    std::println("{}", list);
}
void ctor_demos()
{
    // 1.a.1) 直接初始化
    {
        char array[]{'a', 'b', '\0', 'c'};
        // 参数类型可转换为结果值类型:
        auto str_to = std::ranges::to<std::string>(array);
        // 等价于
        std::string str(array);
        // 结果类型不是输入范围:
        auto re_to = std::ranges::to<std::regex>(array)<span class="

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 适用范围 发布时的行为 修正后的行为
LWG 3984 C++23 R& 不满足 viewable_range 概念时,
ranges::to 的嵌套构造分支会导致程序非良构
改为良构
LWG 4016 C++23 ranges::to 的容器插入分支
使用了插入迭代器
改为直接向容器
追加元素

参考文献

  • C++23 标准 (ISO/IEC 14882:2024):
  • 26.5.7 范围转换 [range.utility.conv]