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> 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*/ = |
(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) | (僅作說明*) |
Range 轉換函式的過載透過呼叫接受一個 Range 的建構函式、一個 `std::from_range_t` 標籤化的 Range 建構函式、一個接受迭代器-哨位對的建構函式,或者透過將源 Range 的每個元素追加到由引數構造的物件中,從作為其第一個引數的源 Range 構造一個新的非檢視物件。
C
的物件:C
不滿足 input_range
,或 std::convertible_to<ranges::range_reference_t<R>, ranges::range_value_t<C>> 為 trueC
的非檢視物件。C
的非檢視物件。C
的非檢視物件:- 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
的非檢視 Range 物件,並在構造後執行以下等效呼叫:
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,這允許在 Range 內進行巢狀的 Range 構造。
令 /*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)...)。
Reference
的元素可以透過成員函式呼叫 emplace_back
、push_back
、emplace
或 insert
被追加到 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
,其 Range 引用型別必須可轉換為 T
。目錄 |
[編輯] 引數
r | - | 一個源 Range 物件 |
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)的,那麼它就是可複製構造的,否則如果它們都是可移動構造 (MoveConstructible)的,那麼它就是可移動構造的。
成員函式 operator()
給定一個先前呼叫 range::to</* 見下文 */>(args...) 得到的物件 G
,當一個指代 G
的泛左值 g
在函式呼叫表示式 g(r) 中被呼叫時,會發生對所儲存物件的呼叫,如同透過以下方式:
- 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
特性測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
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]