分享方式:


範圍配接器

範圍配接器會從某個範圍建立檢視(命名空間中的std::views其中一個 View 類別)。 我們建議您使用配接器來建立檢視,而不是直接建立檢視類型。 配接器是存取檢視的預定方式。 相較於直接建立檢視類型的實例,它們更容易使用,而且在某些情況下更有效率。

檢視是一個輕量型對象,參考範圍中的專案。 檢視可以:

  • 只包含範圍中的特定專案。
  • 表示範圍中項目的轉換。
  • 是範圍中第一 n 個元素的反轉專案。
  • 做為上述項目的組合。

檢視很便宜, O(1)若要複製、指派和終結,無論涉及多少元素。 請考慮下列範例:

// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> input =  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto divisible_by_three = [](const int n) {return n % 3 == 0;};
    auto square = [](const int n) {return n * n;};

    auto x = input | std::views::filter(divisible_by_three)
                   | std::views::transform(square);

    for (int i : x)
    {
        std::cout << i << ' ';
    }
}
0 9 36 81

第一個範圍配接器 filter提供一個檢視,其中包含三 input 個從中除以三個的元素。 另一個範圍配接器 transform會接受檢視,其中包含以三個分隔的元素,並提供這些元素平方的檢視。

當範圍配接器產生檢視時,它不會產生轉換範圍中每個元素以產生該檢視的成本。 只有在您存取該專案時,才會支付在檢視中處理元素的成本。

建立檢視是準備在未來執行工作。 在上一個範例中,建立檢視並不會導致尋找三個元素除名或將這些專案分割的所有元素。 只有在您存取檢視中的專案時,才會發生工作。

檢視的專案通常是用來建立檢視之範圍的實際元素。 檢視通常不擁有專案;它只會參考它們,但 除外 owning_view。 變更專案會變更檢視建立範圍中的專案。 下列範例顯示此行為:

#include <algorithm>
#include <iostream>
#include <ranges>

int main()
{
    int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto even = [](const int n) { return n % 2 == 0; };
    auto x = input | std::views::filter(even); // create a view of the even elements from input

    for (int &i : x)
    {
        std::cout << i << ' '; // 0 2 4 6 8 10
    }
    std::cout << '\n'; 

    std::ranges::fill(x, 42); // changes the evens from input[] to 42
    for (int &i : input) // demonstrates that the even elements in the range are modified
    {
        std::cout << i << ' '; // // 42 1 42 3 42 5 42 7 42 9 42
    }
}

範圍配接器有多種形式。 例如,有範圍配接器可讓您透過下列方式產生檢視:

  • 根據述詞篩選另一個範圍(filter)。
  • 轉換範圍中的專案 (transform)。
  • 分割範圍 (split)。

範圍配接器可以鏈結在一起(組成)。 這就是範圍的力量和彈性最為明顯的地方。 撰寫範圍配接器可讓您克服先前標準範本庫 (STL) 演算法的核心問題,也就是說,它們並不容易鏈結在一起。

命名空間中 std::views 提供下列範圍配接器。 命名空間 std::views 是 的 std::ranges::views便利別名。

範圍配接器 描述
allC++20 建立參考範圍及其元素的檢視。
commonC++20 從沒有的範圍建立具有相同反覆運算器和 sentinel 類型的檢視。
countedC++20 從指定的位置開始,建立範圍中前 n 個項目的檢視。
dropC++20 從另一個檢視建立檢視,略過前面指定的項目數目。
drop_whileC++20 建立檢視,其中包含在卸除符合指定條件之前置元素之後所保留之範圍的專案。
elementsC++20 在範圍中的每個類似 Tuple 值中,建立所選索引的檢視。
emptyC++20 建立沒有元素的檢視。
filterC++20 建立檢視,其中包含符合指定條件之範圍的專案。
iotaC++20 建立包含遞增值序列的檢視。
istreamC++20 建立數據流元素的檢視。
joinC++20 建立檢視,將多個範圍的所有項目合併成單一檢視。
keysC++20 在集合中每個類似 Tuple 的值中,建立第一個索引的檢視。
lazy_splitC++20 根據分隔符將檢視分割成子範圍。
reverseC++20 以反向順序建立範圍專案的檢視。
singleC++20 建立包含一個項目的檢視。
splitC++20 根據分隔符將檢視分割成子範圍。
takeC++20 從另一個檢視建立第一 個 n 個項目的檢視。
take_whileC++20 建立檢視,其中包含符合指定條件之範圍的前置元素。
transformC++20 從另一個檢視建立已轉換元素的檢視。
valuesC++20 在集合中每個類似 Tuple 的值中,建立第二個索引的檢視。

在上表中,範圍配接器通常描述為取得範圍併產生檢視。 為了精確,範圍配接器具有接受下列其中一項的範圍自變數:

  • 型別會模型 view,而 自cv-unqualified變數是右值或可複製。
  • 當您將自變數當做左值傳遞時,它必須模型 range 化並存成只要檢視即可。
  • 當您將 自變數當做右值傳遞時,例如呼叫 owning_view時,它必須建立模型 rangemovable

範圍配接器函式通常是 函式對象,看起來像函式呼叫,並會對可傳遞的類型強制執行條件約束。

您可以將範圍配接器和管道作業的結果傳遞給|預期函式物件的程式代碼。 在下列範例中,範圍配接器所建立的檢視 split 會以函式呼叫的方式傳遞至 transform 範圍配接器,因為 transform 範圍配接器是函式物件。

std::map<int, string> x = {{0, "Hello, world"}, {42, "Goodbye, world"}};
auto y = x | views::values | views::transform(views::split(' '));
// y is a range whose elements are ranges of whitespace-delimited strings from each value in x:
// {{"Hello", "world"}, {"Goodbye", "world"}}

all

建立範圍中所有項目的檢視。

template <ranges::viewable_range R>
constexpr ranges::view auto all(R&& rg) const noexcept;

參數

R
基礎範圍的型別。

rg
要從中建立檢視的範圍。

傳回值

  • 如果 rg 已經是檢視,則為的 rg複本。
  • 如果 rg 非檢視左值,ref_view則表示 。 rg (檢視的存留期會系結至 的 rg存留期。
  • 如果 rg 非檢視右值,例如暫存物件,或是將範圍傳遞至 std::move的結果, owning_view則為 。

使用 std::views::all_t<decltype((rg))> 取得傳回檢視的類型。

備註

此範圍配接器是將範圍轉換成檢視的最佳方式。 從某個範圍建立檢視的其中一個原因是,如果依值傳遞範圍可能很昂貴,則以低成本傳值方式傳遞檢視。

取得某個範圍的檢視是傳遞重量級範圍的實用替代方案,因為檢視成本低廉,無法建立、複製和終結。 可能的例外狀況是 owning_view,這是擁有基礎範圍的檢視。

一般而言,終結檢視的最差案例對於範圍中的元素數目而言,其 O(N) 複雜度。 即使您以N元素終結K檢視複本,整體複雜度仍O(N)是因為基礎範圍只會終結一次。

範例: all

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    auto myRefView = std::views::all(v); // create a ref_view of the vector
    std::cout << myRefView.size() << '\n'; // 10

    auto myOwningView = std::views::all(std::move(v)); // create an owning_view from a moved vector
    std::cout << myRefView.size() << '\n'; // outputs 0 because myOwningView now owns the elements
    std::cout << v.size() << '\n'; // outputs 0 because myOwningView now owns the elements
    std::cout << myOwningView.size(); // 10 
}
10
0
0
10

common

從可能不是的範圍建立具有相同開始反覆運算器和 sentinel 類型的檢視。

template <ranges::viewable_range R>
constexpr ranges::view auto common(R&& rg) const noexcept;

參數

R
基礎範圍的型別。

rg
要從中建立檢視的範圍。

傳回值

  • views::all(rg) 如果 rg 是具有相同反覆運算器和 sentinel 類型的範圍,則為 。
  • common_view(views::all(rg)) 如果 rg 具有不同的反覆運算器和 sentinel 類型, 則為 。

備註

當 API 需要開始反覆運算器和結束 sentinel 具有相同的類型,而您使用的檢視不符合該需求(或您不知道是否這樣做),請使用此範圍配接器來建立 common_view。 它保證開始反覆運算器的類型和結束sentinel的類型相同。

範例: common

// requires /std:c++20 or higher
#include <ranges>
#include <iostream>
#include <numeric>
#include <list>

int main()
{
    std::list<int> lst{1, 2, 3, 4, 5, 6, 7, 8, 9};

    auto firstFive = std::views::take(lst, 5); 
    // firstFive.begin(), firstFive.end() have different types: counted_iterator versus default_sentinel
    // auto r = std::accumulate(firstFive.begin(), firstFive.end(), 0); // Error: accumulate() requires firstFive.begin() and firstFive.end() types to be the same.
    
    auto common = std::views::common(firstFive); // create a common_view that has the same begin/end iterator types
    std::cout << std::accumulate(common.begin(), common.end(), 0); // Now you can call the API because the iterator types are the same. Outputs 15 (1+2+3+4+5) 
}
15

counted

從指定的位置開始,建立範圍第一 count 個項目的檢視。

template<class Iterator>
constexpr auto counted(Iterator&& it, iter_difference_t<Iterator> count);

參數

DifferenceType
計數的類型。

Iterator
反覆運算器的型別。

count
要包含在檢視中的元素數目。 必須是非負數。

  • 如果 count == 0為 ,則會傳回空 span 的 。
  • 如果 count 大於範圍中的項目數目,則行為是未定義的。

it
要以開頭之範圍中專案的反覆運算器。 反覆運算器指向的專案包含在建立的檢視中。

傳回值

span如果 itcontiguous_iterator陣列、向量和其他容器的 ,則會傳回 ,這些容器會連續儲存其元素。 否則會 subrange 傳回 。

備註

包含的項目為 [it, count)

建立檢視之後,即使從變更建立的專案範圍,檢視中的元素數目仍維持不變。 不過,如果基礎範圍變更,從檢視存取專案可能會導致未定義的行為。

範例: counted

// requires /std:c++20 or later
#include <algorithm>
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto pos5 = std::ranges::find(v, 5);
    auto countedView = std::views::counted(pos5, 5);
    for (auto e : countedView) // outputs 5 6 7 8 9
    {
        std::cout << e << ' ';
    }
    std::cout << '\n';

    // You can pass the range directly if it supports input_or_output_iterator, in which case
    // the count starts from the first element
    const char chars[] = { 'H','i',' ','t','h','e','r','e' };
    for (char c : std::views::counted(chars, 2))
    {
        std::cout << c; // outputs Hi
    }
}
5 6 7 8 9
Hi

drop

建立檢視,以排除範圍的前 n 個元素。

1) template<ranges::viewable_range R>
constexpr ranges::view auto drop(R&& rg, ranges::range_difference_t<R> count);

2) template<class DifferenceType>
constexpr /* range closure object */ drop(DifferenceType&& count);

參數

DifferenceType
描述要略過之項目數目的型別。

count
要從 前面卸除的項目 rg數目。 必須是非負數。

  • 如果 count == 0為 ,則會傳回 中的所有 rg 專案。
  • 如果 count 大於 中的 rg項目數目,則會傳回空白檢視。

R
範圍的型別。

rg
用來建立檢視的範圍。

傳回值

基礎範圍的檢視,從前面卸除指定的項目數目。

如果您指定要卸除的項目數目超過基礎範圍中的專案, empty_view 則會傳回 。

傳回的檢視通常是 ,但不一定是 的 drop_view特製化。 也就是說:

備註

建立之後,即使檢視是從變更建立的檢視,檢視中的元素數目仍維持不變。 不過,如果基礎檢視變更,存取傳回檢視中的專案可能會導致未定義的行為。

drop 與相反 take

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | drop(5)。 或者,它可以與函數調用語法搭配使用: drop(collection, 5)drop(5)(collection)

範例: drop

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5};
    auto newView = std::views::drop(v, 3);
    for (auto e : newView) // 4 5
    {
        std::cout << e << ' ';
    }
    std::cout << '\n';

    auto numbers = std::views::iota(0) | std::views::take(10); // build a view of 10 integers
    auto latterHalf = numbers | std::views::drop(5);
    for (auto i : latterHalf)
    {
        std::cout << i << ' '; // 5 6 7 8 9
    }
}
4 5
5 6 7 8 9

drop_while

建立檢視,其中包含在卸除符合指定條件之前置元素之後所保留之範圍的專案。

1) template<ranges::viewable_range R, class P>
constexpr ranges::view auto drop_while(R&& rg, P&& predicate);

2) template<class P>
constexpr /*range adaptor closure*/ drop_while(P&& predicate);

參數

R
範圍的型別。

predicate
決定要從範圍卸除哪些前置元素的條件。

rg
要從中建立檢視的基礎範圍。

傳回值

drop_while_view,包含卸除符合述詞的前置元素時所保留的專案。

備註

一旦述詞傳false回 ,就會停止卸rg除專案。

drop_while 與相反 take_while

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | drop_while(predicate)。 或者,它可以與函數調用語法搭配使用: drop_while(collection, predicate)drop_while(predicate)(collection)

範例: drop_while

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
    auto myView = std::views::drop_while(
        v,
        [](int i) {return i >= 0; });
    print(myView); // -4 5 6

    auto myView2 = v | std::views::drop_while(
        [](int i) {return i < 5; });
    print(myView2); // 5 6
}
-4 5 6
5 6

elements

建立 elements_view,這是範圍中每個類似 Tuple 值之所選索引的檢視。 例如,假設有一個值範圍 std::tuple<string, int> ,請從每個 Tuple 建立 elements_view 所有元素的 string

template<ranges::viewable_range R, size_t N>
constexpr ranges::view auto elements<N>(R&& rg);

參數

N
要從每個類似 Tuple 的值中選取的專案索引,以包含在檢視中。

R
基礎範圍的型別。

rg
要從中建立檢視的 Tuple 類似值範圍。

傳回值

elements_view,其中包含集合中每個類似 Tuple 值的選取索引。

範例: elements

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>

int main()
{
    std::map<std::string, int> cpp_standards
    {
        {"C++98", 1998},
        {"C++03", 2003},
        {"C++11", 2011},
        {"C++14", 2014},
        {"C++17", 2017},
        {"C++20", 2020}
    };

    // Create an elements_view of all the string elements from each tuple
    for (int const year : std::views::elements<1>(cpp_standards))
    {
        std::cout << year << ' '; // 2003 2011 2014 2017 1998 2020
    }
    std::cout << '\n';

    // Another way, using |: create an elements_view of all the int elements from each tuple
    for (auto&& name : cpp_standards | std::views::elements<0>)
    {
        std::cout << name << ' '; // C++03 C++11 C++14 C++17 C++98 c++20
    }
}
2003 2011 2014 2017 1998 2020
C++03 C++11 C++14 C++17 C++98 c++20

empty

建立 , empty_view這是沒有元素的檢視。

template<class T>
inline constexpr empty_view<T> empty{};

參數

T
檢視中專案的型別。 檢視需要元素類型,即使沒有專案也一樣。

傳回值

empty_view

備註

empty_view當您呼叫需要檢視但不需要處理其任何元素的程序代碼時,可能會很有用。

範例: empty

// requires /std:c++20 or higher
#include <ranges>
#include <iostream>

int main()
{
    auto anEmptyView = std::views::empty<int>;
    bool isNotEmpty = (bool)anEmptyView;
    std::cout << boolalpha << isNotEmpty << "\n"; // false
}
false

filter

建立檢視,其中包含符合指定條件之範圍的專案。

1) template<ranges::viewable_range R, class P>
    requires {filter_view(forward<R>(rg), forward<P>(predicate));}
constexpr ranges::view auto filter(R&& rg, P&& predicate);

2) template<class P>
constexpr /*range adaptor closure*/ filter(P&& predicate);

參數

P
述詞的類型。

predicate
決定要保留在範圍中的項目的條件。

R
基礎範圍的型別。

rg
要從中建立檢視的範圍。

傳回值

filter_view,包含符合述詞之範圍的專案。

備註

為了效率起見,當您搭配管道使用 filtertransform 時,請執行filter第一個動作,以便只transform保留|您想要保留的專案。

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | filter(predicate)。 或者,它可以與函數調用語法搭配使用: filter(collection, predicate)filter(predicate)(collection)

範例: filter

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{0, 1, 2, 3, -4, 5, 6};
    auto myView = std::views::filter(v, [](int i) {return i < 5; });
    print(myView); // 0 1 2 3 -4

    auto myView2 = v | std::views::filter([](int i) {return i < 5; }); // pipe syntax
    print(myView2); // 0 1 2 3 -4
}
0 1 2 3 -4
0 1 2 3 -4

iota

建立包含遞增值序列的檢視。 序列可以系結或無法系結。

template<class V>
constexpr ranges::view auto iota(V&& startValue); // create an unbounded sequence of incrementing values

template<class V, class E>
constexpr ranges::view auto iota(V&& startValue, E&& endValue); // create a bounded sequence of incrementing values

參數

E
結束值的型別。

S
開始值的型別。

startValue
序列中的第一個值。

endValue
此值是序列中最後一個值的過去值。 例如, std::views::iota(0, 5) 產生具有 值的 0,1,2,3,4檢視。

傳回值

iota_view遞增值序列的 。

備註

對於未系結的序列,在達到數據類型的最大值之後,行為是未定義的。

範例: iota

// requires /std:c++20 or later
#include <ranges>
#include <iostream>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    // create an iota view with its range adaptor (preferred)
    print(std::views::iota(0, 5)); // outputs 0 1 2 3 4
    
    // create an iota_view class directly
    std::ranges::iota_view letters{'a', 'f'};
    print(letters); // a b c d e
}
0 1 2 3 4
a b c d e

istream

建立數據流元素的檢視。

template <class Val>
views::istream<Val>(str);

參數

str
資料流物件。 其類型衍生自的 std::basic_istream特製化。

Val
要從數據流擷取的項目類型。

傳回值

basic_istream_view

此範圍配接器相當於 ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str),其中 U 是的類型 str

範例: istream

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <sstream>
#include <vector>

int main()
{
    std::istringstream doubles{"1.1 2.2 3.3 4.4 5.5"};
    for (const auto& elem : std::views::istream<double>(doubles))
    {
        std::cout << elem << ' '; // 1.1 2.2 3.3 4.4 5.5
    }
}
1.1 2.2 3.3 4.4 5.5

join

建立檢視,將多個範圍的所有項目合併成單一檢視。

1) template <ranges::viewable_range R>
[[nodiscard]] constexpr ranges::view auto join(R&& rg) const noexcept;

2) inline constexpr /*range adaptor closure*/ join();

參數

R
基礎範圍的型別。

rg
要從中建立檢視的範圍。

傳回值

join_view,包含基礎範圍中所有範圍的專案。

範例: join

#include <iostream>
#include <vector>
#include <ranges>
#include <string>

int main()
{
    // a range of two ranges
    std::vector<std::string> rangeOfRanges[2]{{"C++20", "contains:"}, {"ranges", "modules", "concepts & more."}};

    for (const auto& elem : std::views::join(rangeOfRanges))
    {
        std::cout << elem << ' ';
    }
}
C++20 contains: ranges modules concepts & more.

備註

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | join。 或者,它可以與函數調用語法搭配使用: join(collection)

keys

keys_view在集合中每個類似 Tuple 的值中,建立第一個索引的 。 這對於從關聯容器擷取密鑰很有用。 例如,假設 有一個範圍 std::tuple<string, int>,請建立檢視,其中包含每個 Tuple 中的所有 string 專案。

template <ranges::viewable_range R>
constexpr auto keys(R&& rg);

參數

R
基礎範圍的型別。

傳回值

keys_view,包含範圍中每個 Tuple 類似值的第一個索引。

範例: keys

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>

int main()
{
    // ========== extract keys from a map

    std::map<std::string, int> cpp_standards
    {
        {"C++98", 1998},
        {"C++03", 2003},
        {"C++11", 2011},
        {"C++14", 2014},
        {"C++17", 2017},
        {"C++20", 2020}
    };

    // Extract all of the keys from the map
    for (std::string standards : std::views::keys(cpp_standards))
    {
        std::cout << standards << ' '; // C++03 C++11 C++14 C++17 C++98 C++20
    }
    std::cout << '\n';

    // ========== Extract keys from a pair

    std::vector<std::pair<std::string, int>> windows
    {
        {"Windows 1.0", 1985},
        {"Windows 2.0", 1987},
        {"Windows 3.0", 1990},
        {"Windows 3.1", 1992},
        {"Windows NT 3.1", 1993},
        {"Windows 95", 1995},
        {"Windows NT 4.0", 1996},
        {"Windows 95", 1995},
        {"Windows 98", 1998},
        {"Windows 1.0", 1985},
        {"Windows 2000", 2000}
    };
    
    // Another way to call the range adaptor is by using '|'
    for (std::string version : windows | std::views::keys)
    {
        std::cout << version << ' '; // Windows 1.0 Windows 2.0 Windows 3.0 ...
    }
}
C++03 C++11 C++14 C++17 C++98 C++20
Windows 1.0 Windows 2.0 Windows 3.0 Windows 3.1 Windows NT 3.1 Windows 95 Windows NT 4.0 Windows 95 Windows 98 Windows 1.0 Windows 2000

lazy_split

根據分隔符將範圍分割成子範圍。 分隔符可以是單一專案或項目的檢視。

1) template<viewable_range R, class Pattern>
constexpr view auto lazy_split(R&& rg, Pattern&& delimiter);

2) template<class Pattern>
constexpr /*range adaptor closure*/ lazy_split(Pattern&& delimiter);

參數

delimiter
單一值,或指定分割範圍位置的值序列。

Pattern
分隔符的類型。

R
要分割的範圍類型。

rg
要分割的範圍。

傳回值

lazy_split_view,其中包含一或多個子範圍,而且是分割上delimiter原始範圍的結果。

備註

分隔符不是結果的一部分。 例如,如果您在 值2上分割範圍,您會得到兩個子範圍1,2,313

相關的配接器為 split。 [split_view](split-view-class.md) and lazy_split_view' 之間的主要差異如下:

檢視 可以分割 const 範圍 範圍反覆運算器
split_view 支援 forward_range 或更新版本
lazy_split_view input_range 或更新版本

最好 split_view 是因為它更有效率,除非您必須分割為 const的範圍。

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | lazy_split(delimiter)。 或者,它可以與函數調用語法搭配使用: lazy_split(collection, delimiter)lazy_split(delimiter)(collection)

範例: lazy_split

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> rg{1, 2, 3, 1, 2, 3, 4, 5, 6};

    // split on a single element
    for (const auto& sub : rg | std::views::split(3))
    {
        // outputs:
        // 1 2
        // 1 2
        // 4 5 6
        for (const auto& elem : sub)
        {
            std::cout << elem << ' ';
        }
        std::cout << '\n';
    }

    // split on a sequence of elements
    int delimiters[] = {2, 3};
    for (const auto& subrange : std::views::split(rg, delimiters))
    {
        // outputs 1 1 4 5 6
        for (auto& i : subrange)
        {
            std::cout << i << " ";
        }
    }
}
1 2
1 2
4 5 6
1 1 4 5 6

reverse

以反向順序建立範圍專案的檢視。

1) template<viewable_range R>
constexpr ranges::view auto reverse(R&& rg);

2) inline constexpr /*range adaptor closure*/ reverse();

參數

R
要反轉之基礎範圍的型別。

rg
要反轉的範圍。

傳回值

以反向順序呈現基礎範圍的元素的檢視。 傳回的檢視通常是 ,但不一定是 的 reverse_view特製化。 也就是說:

  • 如果 V 是的 reverse_view特製化 ,則結果為自變數的基礎檢視。 雙反轉是無作業(沒有作業)。
  • 如果 V 具有 表單 subrange<reverse_iterator<I>, reverse_iterator<I>>,則結果為 subrange 未包裝反覆運算器的 。 雙反轉是無作業。
  • 否則,結果是 reverse_view

備註

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | reverse。 或者,它可以與函數調用語法搭配使用: reverse(collection)

範例: reverse

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
    auto rv = v | std::views::reverse; // using the pipe syntax  

    for (auto &&e : rv) // outputs 6 5 -4 3 2 1 0
    {
        std::cout << e << ' ';
    }
    std::cout << '\n';

    // using the range adaptor without using the pipe syntax
    auto rv2 = std::views::reverse(v);
    for (auto &&e : rv2) // outputs 6 5 -4 3 2 1 0
    {
        std::cout << e << ' ';
    }
}
6 5 -4 3 2 1 0
6 5 -4 3 2 1 0

single

建立 single_view,這是包含一個項目的檢視。

template<class T>
constexpr ranges::view auto single(T&& t);

參數

T
檢視中專案的型別。

t
要儲存在檢視中的專案值。

傳回值

single_view,其中包含 t

備註

此檢視適用於測試目的,適用於呼叫需要提供檢視的檢視中至少有一個項目的程序代碼。

範例: single

// requires /std:c++20 or higher
#include <ranges>
#include <string>
#include <tuple>
#include <iostream>

int main()
{
    auto sv = std::views::single(7);
    std::cout << sv.front() << " " << *sv.data() << "\n"; // 7 7
    
    auto sv2 = std::views::single(<std::tuple<double, std::string>{6502, "8-bit"});
    std::cout << std::get<0>(sv2[0]) << " " << std::get<1>(sv2[0]) << "\n"; // 6502 8-bit
}
7 7
6502 8-bit

split

根據分隔符將檢視分割成子範圍。 分隔符可以是單一專案或元素序列。

1) template<viewable_range R, class Pattern>
constexpr view auto split(R&& rg, Pattern&& delimiter);

2) template<class Pattern>
constexpr /*range adaptor closure*/ split(Pattern&& delimiter);

參數

delimiter
單一值,或指定分割範圍位置的值序列。

Pattern
分隔符的類型。

R
要分割的基礎範圍型別。

rg
要分割的範圍。

傳回值

split_view,其中包含一或多個子範圍。

備註

分隔符不是結果的一部分。 例如,如果您在 值2上分割範圍,您會得到兩個子範圍1,2,313

相關的配接器為 lazy_split。 和 lazy_split_view 之間的split_view主要差異如下:

檢視 可以分割 const 範圍 範圍類型
split_view 支援 forward_range 或更新版本
lazy_split_view 支援 input_range 或更新版本

最好 split_view 是因為它更有效率,除非您必須分割為 const的範圍。

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | split(delimiter)。 或者,它可以與函數調用語法搭配使用: split(collection, 5)split(5)(collection)

範例: split

// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> rg{ 1, 2, 3, 1, 2, 3, 4, 5, 6 };

    // split on a single element, 3
    for (const auto& sub : rg | std::views::split(3))
    {
        // This prints out:
        // 1,2
        // 4,5,6
        for (const auto& elem : sub)
        {
            std::cout << elem << ' ';
        }
        std::cout << '\n';
    }

    // split on a sequence of elements, 2,3
    int delimiters[] = {2, 3};
    for (const auto& subrange : std::views::split(rg, delimiters))
    {
        // outputs 1 1 4 5 6
        for (auto& i : subrange)
        {
            std::cout << i << " ";
        }
    }
}
1 2
1 2
4 5 6
1 1 4 5 6

take

建立檢視,其中包含從範圍前端擷取的指定項目數目。

1) template<ranges::viewable_range R>
constexpr ranges::view auto take(R&& rg, ranges::range_difference_type<R> count);

2) template<class DifferenceType>
constexpr /*range adaptor closure*/ take(DifferenceType&& count); 

參數

R
基礎範圍的型別。

rg
要從中建立檢視的範圍。

count
要從 前面取得的項目 rg數目。

傳回值

傳回的檢視通常是 ,但不一定是 的 take_view特製化。 具體而言:

備註

如果您指定要接受的項目數目超過 存在於 中 rg,則會取得所有元素。

take 與相反 drop

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | take(5)。 或者,它可以與函數調用語法搭配使用: take(5, collection)take(5)(collection)

範例: take

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::string s{ "abcdefg" };
    auto myView = std::views::take(s, 3);
    for (auto c : myView)
    {
        std::cout << c << ' '; // a b c
    }

    std::cout << std::endl;

    for (auto c : s | std::views::take(3)) // pipe syntax
    {
        std::cout << c << ' '; // a b c
    }
}
a b c
a b c

take_while

建立檢視,其中包含符合指定條件之範圍的前置元素。

1) template<ranges::viewable_range R, class P>
constexpr ranges::view auto take_while(R&& rg, P&& predicate);

2) template<class P>
constexpr /*range adaptor closure*/ take_while(P&& predicate);

參數

P
述詞的類型。

predicate
決定要從範圍複製哪些前置元素的條件。

R
基礎範圍的型別。

rg
要從中建立檢視的範圍。

傳回值

take_while_view,包含符合範圍中指定準則的第一個專案count

備註

停止在述詞傳回false或範圍用完項目之後從 rg 中擷取元素。

take_while 與相反 drop_while

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | take_while(pred)。 或者,它可以與函數調用語法搭配使用: take_while(collection, pred)take_while(pred)(collection)

範例: take_while

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
    auto myView = std::views::take_while(
        v, [](int i) {return i >= 0; });
    print(myView); // 0 1 2 3

    print(v | std::views::take_while( // 0 1 2 3 -4
        [](int i) {return i < 5; })); // pipe syntax
}
0 1 2 3
0 1 2 3 -4

transform

建立項目的檢視,每個檢視都是指定範圍中項目的轉換。

1) template<viewable_range R, class F>
constexpr ranges::view auto transform(R&& rg, F&& fun);

2) template<class F>
constexpr /*range adaptor closure*/ transform(F&& fun);

參數

F
要轉換專案之函式物件的型別。

R
基礎範圍的型別。

fun
轉換專案的函式。

rg
要從中建立檢視的範圍。

傳回值

transform_view,包含的已轉換專案rg

備註

為了提高效率,當您撰寫 filtertransform時,請執行第一個動作 filter ,以便您 transform 只保留您想要保留的專案。

稍早顯示為 「2)」 的程式代碼可以搭配管道語法使用: collection | transform(fun)。 或者,它可以與函數調用語法搭配使用: transform(collection, fun)transform(fun)(collection)

範例: transform

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>

void print(auto&& v)
{
    for (auto&& x : v)
    {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<int> v{0, 1, 2, 3, -4, 5, 6};
    auto myView = std::views::transform(v, [](int i) {return i * 2; });
    print(myView); // 0 2 4 6 -8 10 12

    print(v | std::views::transform( // 0 2 4 6 -8 10 12
        [](int i) {return i * 2; })); // pipe syntax
}
0 2 4 6 -8 10 12
0 2 4 6 -8 10 12

values

values_view建立 ,其中包含集合中每個 Tuple 類似值的第二個索引。 這對於在關聯容器中檢視值很有用。 例如,假設有一系列 std::tuple<string, int> 值,請建立包含每個 Tuple 中所有 int 元素的檢視。

template <range::viewable_range R>
constexpr ranges::view auto values(R&& rg);

參數

R
基礎範圍的型別。

rg
類似 Tuple 值的基礎範圍。

傳回值

從第二個 values_view 索引建置至範圍中每個類似 Tuple 的值的 。

範例: values

// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>

int main()
{
    // ========== working with a map

    std::map<std::string, int> cpp_standards
    {
        {"C++98", 1998},
        {"C++03", 2003},
        {"C++11", 2011},
        {"C++14", 2014},
        {"C++17", 2017},
        {"C++20", 2020}
    };

    // Extract all of the years from the map
    for (int years : std::views::values(cpp_standards))
    {
        std::cout << years << ' '; // 2003 2011 2014 2017 1998 2020
    }
    std::cout << '\n';

    // ========== working with pairs

    std::vector<std::pair<std::string, int>> windows
    {
        {"Windows 1.0", 1985},
        {"Windows 2.0", 1987},
        {"Windows 3.0", 1990},
        {"Windows 3.1", 1992},
        {"Windows NT 3.1", 1993},
        {"Windows 95", 1995},
        {"Windows NT 4.0", 1996},
        {"Windows 95", 1995},
        {"Windows 98", 1998},
        {"Windows 1.0", 1985},
        {"Windows 2000", 2000}
    };

    // Another way to call the range adaptor by using '|'
    // Create a values_view that contains the year from each pair
    for (int years : windows | std::views::values)
    {
        std::cout << years << ' '; // 1985 1987 1990 1992 ...
    }
}
2003 2011 2014 2017 1998 2020
1985 1987 1990 1992 1993 1995 1996 1995 1998 1985 2000

範圍配接器類型別名

all_t

提供傳回之檢視 all 的類型。

template <ranges::viewable_range R>
using all_t = decltype(views::all(std::declval<R>()));

參數

R
基礎範圍的型別。

傳回值

傳回之檢視 all 的類型: decltype(views::all(std::declval<R>()))

範例: all_t

#include <ranges>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    auto myView = std::views::all(v);
    std::views::all_t<decltype((v))> &viewType = myView;
}

另請參閱

<ranges>
<ranges> 概念
檢視類別