はじめに
従来のC++標準ライブラリ(STL)アルゴリズムは、sort(v.begin(), v.end())
のように、必ずコンテナのイテレータをペアで渡す必要がありました。これは冗長であり、end()
を begin()
と書き間違えるといった単純なミスも起こり得ました。
C++20で導入されたRangesライブラリは、この問題を解決します。Rangesは、vector
やarray
のようなコンテナそのものを「レンジ(要素の範囲)」という単一の概念として扱うことができます。
この記事では、Rangesライブラリがもたらす3つの主要な改善点について、その概要を解説します。
- レンジ対応アルゴリズム: イテレータのペアの代わりに、コンテナを直接渡せる。
- レンジアダプタ(ビュー): パイプ(
|
)を使って、複数の操作をメソッドチェーンのように繋げられる。 - コンテナへの変換: ビューが表現する結果を、簡単に新しいコンテナに変換できる。
1. レンジ対応アルゴリズム
Rangesライブラリは、従来のアルゴリズムのレンジ対応版を提供します。これにより、コードが非常に簡潔になります。
サンプルコード
#include <iostream>
#include <vector>
#include <algorithm> // std::count
#include <ranges> // std::ranges::count
using namespace std;
int main() {
vector<int> numbers = {10, 20, 30, 20, 40};
// 従来の方法
long count1 = std::count(numbers.begin(), numbers.end(), 20);
// レンジ対応の方法
long count2 = std::ranges::count(numbers, 20);
cout << "20の個数 (従来): " << count1 << endl;
cout << "20の個数 (レンジ): " << count2 << endl;
return 0;
}
解説: std::ranges::count
では、.begin()
と .end()
を渡す必要がなく、コンテナ numbers
を直接渡すだけで済みます。
2. レンジアダプタ(ビュー)とパイプ演算子
Rangesの最も強力な機能が、ビューとパイプ演算子 (|
) です。ビューは、元のデータをコピーせず、データに対する操作(フィルタリングや変換など)の連鎖を定義する軽量なオブジェクトです。
サンプルコード
#include <iostream>
#include <vector>
#include <ranges>
namespace views = std::ranges::views;
int main() {
vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// データの流れ: data -> 偶数のみフィルタ -> 各要素を10倍
auto view = data
| views::filter([](int n){ return n % 2 == 0; })
| views::transform([](int n){ return n * 10; });
// ビューをループ処理
for (int result : view) {
cout << result << " ";
}
cout << endl;
return 0;
}
実行結果: 20 40 60 80 100
解説: data | views::filter(...) | views::transform(...)
というコードは、「data
の中から、偶数のものだけを(filter
)、10倍(transform
)してくれ」という処理の流れを、左から右へ、非常に直感的に表現しています。従来のfor
ループとif
文を組み合わせる方法よりも、はるかに宣言的で読みやすくなります。
3. ビューからコンテナへの変換 (C++23)
ビューはあくまで「眺め」であり、それ自体はデータを保持しません。ビューが示す結果を、新しいvector
やlist
として実体化したい場合は、C++23で導入された std::ranges::to
を使います。
サンプルコード (C++23)
#include <iostream>
#include <vector>
#include <list>
#include <ranges>
namespace views = std::ranges::views;
namespace ranges = std::ranges;
int main() {
vector<int> source = {1, 2, 3, 4, 5, 6};
// 偶数だけをフィルタリングしたビューを、新しいlistに変換
list<int> evens = source
| views::filter([](int n){ return n % 2 == 0; })
| ranges::to<list<int>>();
for (int n : evens) {
cout << n << " ";
}
cout << endl; // -> 2 4 6
return 0;
}
解説: パイプの最後に | ranges::to<コンテナ型>()
を繋げるだけで、ビューの結果が新しいコンテナに変換されます。
まとめ
今回は、C++20のRangesライブラリがもたらす主要な機能の概要を解説しました。
- イテレータのペアの代わりに、コンテナを直接アルゴリズムに渡せるようになった。
- ビューとパイプ演算子 (
|
) を使うことで、宣言的で直感的なデータ操作が可能になった。 - ビューの結果を、簡単に新しいコンテナに変換できるようになった (C++23)。
Rangesライブラリは、C++でのデータ操作を、より安全で、より表現力豊かで、より効率的なものへと進化させる、非常に重要な機能です。