レンジ アルゴリズムを使用したセンチネルとコンセプト

C++20 の範囲ライブラリはセンチネルをサポートしています。センチネルは範囲の終わりを表し、一般化された終了イテレータと見なすことができます。

begin iterator と end Sentinel によって提供される範囲は、反復できるアイテムのグループを指定します。 STL のコンテナーは、終了イテレーターが範囲の終わりをマークするため、範囲です。

センチネル

次の例では、C 文字列と std::vector<int> にセンチネルを使用しています。 .
// sentinel.cpp

#include <iostream>
#include <algorithm>
#include <compare>
#include <vector>

struct Space {  // (1)
bool operator== (auto pos) const {
 return *pos == ' '; 
 }
};

struct NegativeNumber {  // (2)
 bool operator== (auto num) const {
 return *num < 0; 
 }
};

struct Sum { // (7)
 void operator()(auto n) { sum += n; }
 int sum{0};
};

int main() {

 std::cout << '\n';

 const char* rainerGrimm = "Rainer Grimm";
 
 std::ranges::for_each(rainerGrimm, Space{}, [] (char c) { std::cout << c; }); // (3)
 std::cout << '\n';
 for (auto c: std::ranges::subrange{rainerGrimm, Space{}}) std::cout << c; // (4)
 std::cout << '\n';

 std::ranges::subrange rainer{rainerGrimm, Space{}}; // (5)
 std::ranges::for_each(rainer, [] (char c) { std::cout << c << ' '; }); // (6)
 std::cout << '\n';
 for (auto c: rainer) std::cout << c << ' ';
 std::cout << '\n';
 

 std::cout << "\n";


 std::vector<int> myVec{5, 10, 33, -5, 10};

 for (auto v: myVec) std::cout << v << " ";
 std::cout << '\n';

 auto [tmp1, sum] = std::ranges::for_each(myVec, Sum{});
 std::cout << "Sum: " << sum.sum << '\n'; // (8)

 auto [tmp2, sum2] = std::ranges::for_each(std::begin(myVec), NegativeNumber{}, 
 Sum{} ); 
 std::cout << "Sum: " << sum2.sum << '\n'; // (9)

 std::ranges::transform(std::begin(myVec), NegativeNumber{},  // (10)
 std::begin(myVec), [](auto num) { return num * num; });
 std::ranges::for_each(std::begin(myVec), NegativeNumber{},  // (11)
 [](int num) { std::cout << num << " "; });
 std::cout << '\n';
 for (auto v: std::ranges::subrange{ std::begin(myVec), NegativeNumber{}}) { // (12)
 std::cout << v << " ";
 }

 std::cout << "\n\n";
 
}

このプログラムは、スペース (1 行目) と NegativeNumber の 2 つのセンチネルを定義します。 (2行目)。どちらも等号演算子を定義します。 <compare> のおかげで ヘッダー、コンパイラは非等号演算子を自動生成します。 std::ranges_for_each などのアルゴリズムを使用する場合は、不等号演算子が必要です。 または std::ranges::transform センチネル付き。センチネル Space から始めましょう .
行 (3) は番兵 Space{} を適用します 文字列 "rainerGrimm に直接 ". std::ranges::subrange の作成 (4 行目) 範囲ベースの for ループでセンチネルを使用できるようにします。 std::ranges::subrange を定義することもできます アルゴリズム std::ranges::for_each (5 行目) または範囲ベースの for ループ (6 行目) で直接使用します。
2 番目の例では std::vector<int> を使用します。 、値 {5, 10, 33, -5, 10} で埋められます .センチネル NegativeNumber 数値が負かどうかを調べます。まず、関数オブジェクト Sum を使用してすべての値を合計します (7 行目)。 std::ranges::for_each ペア (it, func) を返します . it センチネルと func の後継です。 範囲に適用される関数オブジェクト。構造化バインディングのおかげで、変数 sum を直接定義できます と sum2 それらの値を表示します (8 行目と 9 行目)。 std::ranges::for_each センチネル NegativeNumber を使用 .したがって、sum2 センチネルまでの合計を持っています。呼び出し std::ranges::transform (10 行目) 各要素をその正方形に変換します: [](auto num){ return num * num} .センチネル NegativeNumber. で変換が停止します 行 11 と行 12 は、変換された値を表示します。
最後に、プログラムの出力を次に示します。

STL の古典的なアルゴリズムを使用する必要があるのか​​、それともコンテナの範囲ペンダントを使用する必要があるのか​​?両方を比較して、この質問に答えましょう。

std アルゴリズムと std::ranges の比較 アルゴリズム

比較の詳細に入る前に、全体像を示したいと思います:

範囲は数値をサポートしていません

範囲は functional の機能をサポートします 、および algorithm ヘッダーですが、numeric の機能 ヘッダ。 The numeric ヘッダーには が含まれます std::gcd, std::midpoint, std::iota, などの数学関数 または std::accumulate.

もっと興味深い違いについて書きましょう。

コンセプトのサポート

std::ranges アルゴリズムは概念の代表的なものです。

古典的な std::sort の比較から始めましょう そして新しい std::ranges::sort . std::sortstd::ranges::sort 一定時間内に範囲の各要素にアクセスできるランダムアクセス反復子が必要です。 std::sort に関連する 2 つのオーバーロードを次に示します。 そして std::ranges::sort .
  • std::sort
template< class RandomIt >
constexpr void sort( RandomIt first, RandomIt last );

  • std:ranges::sort
template <std::random_access_iterator I, std::sentinel_for<I> S,
 class Comp = ranges::less, class Proj = std::identity>
requires std::sortable<I, Comp, Proj>
constexpr I sort(I first, S last, Comp comp = {}, Proj proj = {});
std::sort を呼び出すとどうなるか または std::ranges::sort std::list などのコンテナを使用 双方向イテレータのみをサポートしていますか?

std::sort

// sortVector.cpp

#include <algorithm>
#include <list>
 
int main() {
 
 std::list<int> myList{1, -5, 10, 20, 0};
 std::sort(myList.begin(), myList.end());
 
}

プログラム sortVector.cpp のコンパイル GCC を使用すると、1090 行の壮大なエラー メッセージが表示されます。

std::ranges::sort

// sortRangesVector.cpp

#include <algorithm>
#include <list>
 
int main() {
 
 std::list<int> myList{1, -5, 10, 20, 0};
 std::ranges::sort(myList.begin(), myList.end());
 
}

std::ranges::sort の使用 std::sort reduces の代わりに エラーメッセージが大幅に。現在、57 行のエラー行が表示されています。

正直なところ、GCC のエラー メッセージは読みやすいはずですが、私はそれを責めません。私たちはまだ概念をサポートする初期段階にあります。 57 行のうち最初の 10 行を以下に示します。重要なメッセージを赤でマークしました。

次にどのメンタリング プログラムを実装する必要がありますか?

現在の指導プログラム「Fundamentals for C++ Professionals」は大成功を収めており、35 人以上が参加しています。ここで、追加のメンタリング プログラムを実施します。それらはすべて、私の C++ の本、投稿、およびクラスに基づいています。

ここで選択してください:https://www.modernescpp.com/index.php/my-next-mentoring-program

次は?

std の比較はまだ終わっていません と std::ranges アルゴリズム。次の投稿では、std::ranges という統一されたルックアップ ルールについて書きます。 アルゴリズムは、追加の安全保証を提供します。