範囲アダプター
範囲アダプターは、範囲から view ( View クラスの 1 つ std::views
名前空間内) を作成します。 ビューの種類を直接作成するのではなく、アダプターを使用してビューを作成することをお勧めします。 アダプターは、ビューにアクセスするための目的の方法です。 ビューの種類のインスタンスを直接作成するよりも、使いやすく、効率的な場合もあります。
ビューは、範囲の要素を参照する軽量オブジェクトです。 ビューは次のことができます。
- 範囲の特定の要素のみで構成されます。
- 範囲からの要素の変換を表します。
- 範囲の最初の
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
は、3 つ割り切れる input
の要素を含むビューを提供します。 もう 1 つの範囲アダプター transform
は、3 で割り切れる要素を含むビューを受け取り、それらの要素の正方形のビューを提供します。
範囲アダプターがビューを生成しても、そのビューを生成するために範囲内のすべての要素を変換するコストは発生しません。 ビュー内の要素を処理するためのコストは、その要素にアクセスした場合にのみ支払われます。
ビューの作成は、将来の作業を行う準備です。 前の例では、ビューを作成しても、3 つの要素で割り切れるすべての要素が検索されたり、それらの要素が 2 乗されたりすることはありません。 作業は、ビュー内の要素にアクセスする場合にのみ行われます。
通常、ビューの要素は、ビューの作成に使用される範囲の実際の要素です。 通常、ビューは要素を所有していません。 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 |
ない範囲から同じ反復子とセンチネル型を持つビューを作成します。 |
counted C++20 |
指定した位置から始まる範囲の最初の n 要素のビューを作成します。 |
drop C++20 |
別のビューからビューを作成し、指定した数の要素を前面からスキップします。 |
drop_while C++20 |
指定した条件に一致する先頭の要素が削除された後に残る範囲の要素を含むビューを作成します。 |
elements C++20 |
範囲内の各タプルに似た値に、選択したインデックスのビューを作成します。 |
empty C++20 |
要素のないビューを作成します。 |
filter C++20 |
指定した条件に一致する範囲の要素を含むビューを作成します。 |
iota C++20 |
増加する値のシーケンスを含むビューを作成します。 |
istream C++20 |
ストリームの要素に対してビューを作成します。 |
join C++20 |
複数の範囲のすべての要素を 1 つのビューに結合するビューを作成します。 |
keys C++20 |
コレクション内の各タプルに似た値に最初のインデックスのビューを作成します。 |
lazy_split C++20 |
区切り記号に基づいてビューをサブ範囲に分割します。 |
reverse C++20 |
範囲の要素のビューを逆の順序で作成します。 |
single C++20 |
1 つの要素を含むビューを作成します。 |
split C++20 |
区切り記号に基づいてビューをサブ範囲に分割します。 |
take C++20 |
別のビューから最初の n 要素のビューを作成します。 |
take_while C++20 |
指定した条件に一致する範囲の先頭要素を含むビューを作成します。 |
transform C++20 |
変換された要素のビューを別のビューから作成します。 |
values C++20 |
コレクション内の各タプルに似た値に、2 番目のインデックスのビューを作成します。 |
前の表では、範囲アダプターは通常、範囲を取得してビューを生成すると説明されています。 正確には、範囲アダプターには、次のいずれかを受け入れる範囲引数があります。
cv-unqualified
型モデルview
。引数は右辺値であるか、コピー可能です。- 左辺値として引数を渡す場合は、ビューに限り、
range
モデル化され、ライブである必要があります。 - 引数を右辺値として渡す場合 (
owning_view
を呼び出す場合など)、range
とmovable
をモデル化する必要があります。
範囲アダプター関数は、通常、関数呼び出しのように見え渡すことができる型に制約を適用する関数オブジェクトです。
範囲アダプターとパイプ操作の結果 (|
) を、関数オブジェクトを必要とするコードに渡すことができます。 次の例では、transform
範囲アダプターが関数オブジェクトであるため、split
範囲アダプターが作成したビューは、関数呼び出しのように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
がビュー以外の左辺値の場合は、rg
を参照するref_view
。 (ビューの有効期間は、rg
の有効期間に関連付けられています)。rg
が一時オブジェクトなどのビュー以外の右辺値である場合、または範囲をstd::move
に渡した結果である場合は、owning_view
。
std::views::all_t<decltype((rg))>
を使用して、返されるビューの型を取得します。
解説
この範囲アダプターは、範囲をビューに変換する最適な方法です。 範囲からビューを作成する理由の 1 つは、値渡しのコストが高くなる可能性がある範囲を低コストで渡すことです。
ビューの作成、コピー、破棄は低コストであるため、範囲のビューを取得することは、重み付け範囲を値渡しする代わりに便利です。 考えられる例外は、基になる範囲を所有するビューである owning_view
です。
一般に、ビューを破棄する最悪のシナリオでは、範囲内の要素の数 O(N)
複雑になります。 N
要素K
ビューのコピーを破棄した場合でも、基になる範囲は 1 回だけ破棄されるため、全体の複雑さが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
の反復子とセンチネルの型が異なる場合は。
解説
API で開始反復子と終了センチネルの型が同じである必要があり、使用しているビューがその要件を満たしていない (または満たしていない場合) 場合は、この範囲アダプターを使用して 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
開始する範囲内の要素を指す反復子。 反復子が指す要素は、作成されたビューに含まれます。
戻り値
it
が、要素を連続して格納する配列、ベクター、およびその他のコンテナーのcontiguous_iterator
である場合、span
が返されます。 それ以外の場合は、 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
の特殊化であるか、random_access_range
とsized_range
の両方であるspan
、basic_string_view
、iota_view
、またはsubrange
の特殊化である場合、結果は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
を作成します。これは、範囲内の各タプルに似た値に、選択したインデックスのビューです。 たとえば、std::tuple<string, int>
値の範囲がある場合は、各タプルからすべてのstring
要素のelements_view
を作成します。
template<ranges::viewable_range R, size_t N>
constexpr ranges::view auto elements<N>(R&& rg);
パラメーター
N
ビューに含めるタプルに似た値から選択する要素のインデックス。
R
基になる範囲の型。
rg
ビューを作成するタプルに似た値の範囲。
戻り値
コレクション内の各タプルに似た値に、選択したインデックスで構成される elements_view
。
例: 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
この値は、シーケンス内の最後の値の 1 つ後にあります。 たとえば、 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 つのビューに結合するビューを作成します。
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
を作成します。 これは、連想コンテナーからキーを抽出する場合に便利です。 たとえば、 std::tuple<string, int>
の範囲を指定すると、各タプルのすべての string
要素で構成されるビューを作成します。
template <ranges::viewable_range R>
constexpr auto keys(R&& rg);
パラメーター
R
基になる範囲の型。
戻り値
範囲内の各タプルに似た値への最初のインデックスで構成される keys_view
。
例: 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 つの要素または要素のビューを指定できます。
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
1 つの値、または範囲を分割する場所を指定する値のシーケンス。
Pattern
区切り記号の型。
R
分割する範囲の型。
rg
分割する範囲。
戻り値
1 つ以上のサブ範囲を含み、delimiter
の元の範囲を分割した結果であるlazy_split_view
。
解説
区切り記号は結果の一部ではありません。 たとえば、値2
の範囲1,2,3
を分割すると、1
と3
の 2 つのサブ範囲が表示されます。
関連するアダプターが split
。 [split_view](split-view-class.md) and
lazy_split_view' の主な違いは次のとおりです。
表示 | const 範囲を分割できます |
範囲反復子 |
---|---|---|
split_view |
いいえ | forward_range 以上をサポート |
lazy_split_view |
はい | input_range 以上 |
const
範囲を分割する必要がない限り、split_view
の方が効率的です。
前に "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
1 つの要素を含むビューである single_view
を作成します。
template<class T>
constexpr ranges::view auto single(T&& t);
パラメーター
T
ビュー内の要素の型。
t
ビューに格納する要素の値。
戻り値
t
を含むsingle_view
。
解説
このビューは、少なくとも 1 つの要素を含むビューで提供する必要があるコードを呼び出すために、テスト目的で役立ちます。
例: 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 つの要素または要素のシーケンスを指定できます。
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
1 つの値、または範囲を分割する場所を指定する値のシーケンス。
Pattern
区切り記号の型。
R
分割する基になる範囲の型。
rg
分割する範囲。
戻り値
1 つ以上のサブ範囲を含む split_view
。
解説
区切り記号は結果の一部ではありません。 たとえば、値2
の範囲1,2,3
を分割すると、1
と3
の 2 つのサブ範囲が表示されます。
関連するアダプターが lazy_split
。 split_view
とlazy_split_view
の主な違いは次のとおりです。
表示 | const 範囲を分割できます |
範囲の種類 |
---|---|---|
split_view |
いいえ | forward_range 以上をサポート |
lazy_split_view |
はい | input_range 以上をサポート |
const
範囲を分割する必要がない限り、split_view
の方が効率的です。
前に "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
の特殊化であるか、random_access_range
とsized_range
の両方であるspan
、basic_string_view
、iota_view
、またはsubrange
の特殊化である場合、結果は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
ビューを作成する範囲。
戻り値
範囲内の指定した条件を満たす最初のcount
要素で構成されるtake_while_view
。
解説
述語が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
ビューを作成する範囲。
戻り値
rg
の変換された要素を含むtransform_view
。
解説
効率を高めるために、 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
コレクション内の各タプルに似た値に 2 番目のインデックスで構成される values_view
を作成します。 これは、連想コンテナー内の値を表示する場合に便利です。 たとえば、 std::tuple<string, int>
値の範囲を指定すると、各タプルのすべての int
要素で構成されるビューが作成されます。
template <range::viewable_range R>
constexpr ranges::view auto values(R&& rg);
パラメーター
R
基になる範囲の型。
rg
タプルに似た値の基になる範囲。
戻り値
2 番目のインデックスから範囲内の各タプルに似た値に構築された values_view
。
例: 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;
}