名稱空間
變體
操作

std::ranges::to

來自 cppreference.com
< cpp‎ | ranges
 
 
範圍庫 (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) (僅作說明*)

Range 轉換函式的過載透過呼叫接受一個 Range 的建構函式、一個 `std::from_range_t` 標籤化的 Range 建構函式、一個接受迭代器-哨位對的建構函式,或者透過將源 Range 的每個元素追加到由引數構造的物件中,從作為其第一個引數的源 Range 構造一個新的非檢視物件。

1) 以下列方式,從 r 的元素構造一個型別為 C 的物件:
1) 如果 std::constructible_from<C, R, Args...>true,則如同透過從源 Range std::forward<R>(r) 和其餘函式引數 std::forward<Args>(args)... 進行直接初始化(而非直接列表初始化)來構造一個型別為 C 的非檢視物件。
2) 否則,如果 std::constructible_from<C, std::from_range_t, R, Args...>true,則如同透過從額外的消歧義標籤 std::from_range、源 Range std::forward<R>(r) 和其餘函式引數 std::forward<Args>(args)... 進行直接初始化(而非直接列表初始化)來構造一個型別為 C 的非檢視物件。
3) 否則,如果以下所有條件都為 true,則如同透過從迭代器-哨位對(ranges::begin(r) 作為迭代器,ranges::end(r) 作為哨位,其中迭代器和哨位型別相同。換句話說,源 Range 必須是 common range)和其餘函式引數 std::forward<Args>(args)... 進行直接初始化(而非直接列表初始化)來構造一個型別為 C 的非檢視物件:
4) 否則,如同透過從其餘函式引數 std::forward<Args>(args)... 進行直接初始化(而非直接列表初始化)來構造一個型別為 C 的非檢視 Range 物件,並在構造後執行以下等效呼叫:

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,這允許在 Range 內進行巢狀的 Range 構造。

否則,程式格式錯誤。
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;                      // 未定義
    pointer operator->() const;                       // 未定義
    /*input-iterator*/& operator++();                 // 未定義
    /*input-iterator*/ operator++(int);               // 未定義
    bool operator==(const /*input-iterator*/&) const; // 未定義

};
(僅作說明*)

/*DEDUCE-EXPR*/ 定義如下:

該呼叫等價於 to<decltype(/*DEDUCE-EXPR*/)>
    (std::forward<R>(r), std::forward<Args>(args)...)
3,4) 返回一個完美轉發呼叫包裝器,它同時也是一個 Range 介面卡閉包物件 (RangeAdaptorClosureObject)
5) 如果滿足 ranges::sized_range 並且有資格進行預留,則為 true
6) 如果一個型別為 Reference 的元素可以透過成員函式呼叫 emplace_backpush_backemplaceinsert 被追加到 Container,則為 true
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) 用於容器的定義中,構造一個輸入 Range R,其 Range 引用型別必須可轉換為 T

目錄

[編輯] 引數

r - 一個源 Range 物件
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)的,那麼它就是可複製構造的,否則如果它們都是可移動構造 (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

如果 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]