範圍配接器
範圍配接器會從某個範圍建立檢視(命名空間中的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
}
}
範圍配接器有多種形式。 例如,有範圍配接器可讓您透過下列方式產生檢視:
範圍配接器可以鏈結在一起(組成)。 這就是範圍的力量和彈性最為明顯的地方。 撰寫範圍配接器可讓您克服先前標準範本庫 (STL) 演算法的核心問題,也就是說,它們並不容易鏈結在一起。
命名空間中 std::views
提供下列範圍配接器。 命名空間 std::views
是 的 std::ranges::views
便利別名。
範圍配接器 | 描述 |
---|---|
all C++20 |
建立參考範圍及其元素的檢視。 |
common C++20 |
從沒有的範圍建立具有相同反覆運算器和 sentinel 類型的檢視。 |
counted C++20 |
從指定的位置開始,建立範圍中前 n 個項目的檢視。 |
drop C++20 |
從另一個檢視建立檢視,略過前面指定的項目數目。 |
drop_while C++20 |
建立檢視,其中包含在卸除符合指定條件之前置元素之後所保留之範圍的專案。 |
elements C++20 |
在範圍中的每個類似 Tuple 值中,建立所選索引的檢視。 |
empty C++20 |
建立沒有元素的檢視。 |
filter C++20 |
建立檢視,其中包含符合指定條件之範圍的專案。 |
iota C++20 |
建立包含遞增值序列的檢視。 |
istream C++20 |
建立數據流元素的檢視。 |
join C++20 |
建立檢視,將多個範圍的所有項目合併成單一檢視。 |
keys C++20 |
在集合中每個類似 Tuple 的值中,建立第一個索引的檢視。 |
lazy_split C++20 |
根據分隔符將檢視分割成子範圍。 |
reverse C++20 |
以反向順序建立範圍專案的檢視。 |
single C++20 |
建立包含一個項目的檢視。 |
split C++20 |
根據分隔符將檢視分割成子範圍。 |
take C++20 |
從另一個檢視建立第一 個 n 個項目的檢視。 |
take_while C++20 |
建立檢視,其中包含符合指定條件之範圍的前置元素。 |
transform C++20 |
從另一個檢視建立已轉換元素的檢視。 |
values C++20 |
在集合中每個類似 Tuple 的值中,建立第二個索引的檢視。 |
在上表中,範圍配接器通常描述為取得範圍併產生檢視。 為了精確,範圍配接器具有接受下列其中一項的範圍自變數:
- 型別會模型
view
,而 自cv-unqualified
變數是右值或可複製。 - 當您將自變數當做左值傳遞時,它必須模型
range
化並存成只要檢視即可。 - 當您將 自變數當做右值傳遞時,例如呼叫
owning_view
時,它必須建立模型range
和movable
。
範圍配接器函式通常是 函式對象,看起來像函式呼叫,並會對可傳遞的類型強制執行條件約束。
您可以將範圍配接器和管道作業的結果傳遞給|
預期函式物件的程式代碼。 在下列範例中,範圍配接器所建立的檢視 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
如果 it
是contiguous_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
特製化。 也就是說:
- 如果
V
是的empty_view
特製化,或 是 、、iota_view
或 的特製化basic_string_view
span
,則subrange
random_access_range
為 和sized_range
,則結果為的V
特製化。 - 否則,結果是
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
// 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
,包含符合述詞之範圍的專案。
備註
為了效率起見,當您搭配管道使用 filter
和 transform
時,請執行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
要從數據流擷取的項目類型。
傳回值
此範圍配接器相當於 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,3
:1
和 3
。
相關的配接器為 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,3
:1
和 3
。
相關的配接器為 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
特製化。 具體而言:
- 如果
V
是的empty_view
特製化,或 是 、、iota_view
或 的特製化basic_string_view
span
,則subrange
random_access_range
為 和sized_range
,則結果為的V
特製化。 - 否則,結果是
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
。
備註
為了提高效率,當您撰寫 filter
和 transform
時,請執行第一個動作 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;
}