std::ranges::to
定义于头文件 <ranges> |
||
template< class C, ranges::input_range R, class... Args > requires (!ranges::view<C>) |
(1) | (自 C++23 起) |
template< template< class... > class C, ranges::input_range R, class... Args > |
(2) | (自 C++23 起) |
template< class C, class... Args > requires (!ranges::view<C>) |
(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*/ = |
(5) | (仅为阐释目的*) |
template< class Container, class Reference > constexpr bool /*container-appendable*/ = |
(6) | (仅为阐释目的*) |
template< class Reference, class C > constexpr auto /*container-appender*/( C& c ); |
(7) | (仅为阐释目的*) |
template< class R, class T > concept /*container-compatible-range*/ = |
(8) | (仅为阐释目的*) |
范围转换函数的重载从源范围构造一个新的非视图对象作为其首个实参,通过调用接受范围的构造函数、接受 std::from_range_t
标记范围构造函数、接受迭代器-哨位对的构造函数,或者通过将源范围的每个元素后向插入到实参构造的对象中。
C
的对象,按照以下方式C
不满足 input_range
或 std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> 为 trueC
的对象,如果 std::constructible_from<C, R, Args...> 为 true。C
的对象,如果 std::constructible_from<C, std::from_range_t, R, Args...> 为 true。C
的对象,如果以下所有条件都为 true- 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
的对象,并在构造后进行以下等效调用
if constexpr (ranges::sized_range<R> && /*reservable-container*/<C>) |
(直到 C++26) |
if constexpr (ranges::approximately_sized_range<R> |
(自 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,则上述操作有效
- 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)...)
如果 ranges::input_range<ranges::range_reference_t<C>> 为 true,则允许在范围内进行嵌套范围构造。
设 /*input-iterator*/ 为仅用于阐释目的的类型,它满足 LegacyInputIterator
struct /*input-iterator*/ { |
(仅为阐释目的*) | |
设 /*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>()...),如果该表达式有效。 - 否则,程序是非良构的。
(std::forward<R>(r), std::forward<Args>(args)...)。
emplace_back
、push_back
、emplace
或 insert
将类型为 Reference
的一个元素附加到 Container
,则为 true。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
,其范围引用类型必须可转换为 T
。目录 |
[编辑] 参数
r | - | 源范围对象 |
args | - | 用于 (1,2) 构造范围或 (3,4) 绑定到范围适配器闭包对象的最后参数的参数列表 |
类型要求 | ||
-C 必须是 cv-非限定类类型 (1,3) |
[编辑] 返回值
ranges::to 返回类型
成员对象
返回的对象行为如同它没有目标对象,以及使用 std::tuple 对象 tup 构造的 std::tuple<std::decay_t<Args>...>(std::forward<Args>(args)...),除了返回对象的赋值行为未指定且名称仅用于说明。
构造函数
ranges::to
(3,4) 的返回类型行为如同其复制/移动构造函数执行成员方式的复制/移动。如果其所有成员对象(如上所述)都是 CopyConstructible,则它是 CopyConstructible,否则是 MoveConstructible。
成员函数 operator()
给定从先前调用 range::to</* 见下文 */>(args...) 获得的对象 G
,当在函数调用表达式 g(r) 中调用指定 G
的泛左值 g 时,将发生对存储对象的调用,如同通过
- ranges::to</* 见下文 */>(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
。
- r 是一个源范围对象,必须满足
如果 g 具有 volatile 限定类型,则程序是非良构的。
[编辑] 异常
仅当非视图对象的构造抛出异常时才抛出。
[编辑] 注释
将元素插入容器可能涉及复制,这可能比移动效率低,因为在间接调用期间会产生左值引用。用户可以选择使用 views::as_rvalue 来适配范围,以便它们的元素在间接调用期间始终产生右值引用,这意味着移动。
使用管道语法时,括号是强制性的。
auto vec = r | std::ranges::to<std::vector>; // Error auto vec = r | std::ranges::to<std::vector>(); // OK
Feature-test 宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_lib_ranges_to_container |
202202L |
(C++23) | 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) 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); } }
输出
[2, 4, 6, 8] [2, 4, 6]
[编辑] 缺陷报告
以下行为更改缺陷报告被追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
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]