yohhoyの日記

技術的メモをしていきたい日記

レンジ to コンテナ変換

次期C++2b(C++23)標準ライブラリに向けて、Rangesから各種コンテナ型への直接変換サポートが検討されている。(PDF)P1206R6では下記の機能追加/拡張を提案している。

  • コンテナ型Cへの変換std::ranges::to<C>レンジアダプタ(range adaptor)
  • 標準コンテナへのstd::from_rangeコンストラクタ追加*1
#include <ranges>
#include <vector>

bool is_prime(int n);

// 100未満の素数を列挙するRange
auto rng = std::views::iota(1)
  | std::views::filter(is_prime)
  | std::views::take_while([](int x) { return x < 100; });

// C++20: 一部Rangeではcommon_viewへの変換が必要
auto cv = rng | std::views::common;
std::vector vec( std::begin(cv), std::end(cv) );
// C++2b(P1206R6)
auto rng = /* (同上) */;

// std::ranges::to<C>レンジアダプタ
auto vec = std::ranges::to<std::vector>( rng );  // 関数記法
auto vec = rng | std::ranges::to<std::vector>;   // パイプライン記法
// std::from_rangeコンストラクタ
std::vector vec( std::from_range, rng );

std::ranges::to<C>レンジアダプタでは、あらゆる実現手段を用いてRange→コンテナ変換を試みる。コンパイル時に下記パターンを試行する:

1. レンジからコンテナCを直接構築
2. std::from_rangeタグ付きコンストラクタを用いたコンテナC構築
3. イテレータペア:std::range::begin(r), std::range::end(r)からコンテナC構築
4. 末尾への要素追加:コンテナC構築後にRange要素を順次末尾に追加

  • 変換先コンテナCが容量指定可能ならば、reserveメンバ関数によりメモリ事前確保を試みる。
  • 末尾への要素追加にはpush_backまたはinsertメンバ関数を利用する。

5. 入れ子Range対応:変換先コンテナ要素が子Rangeかつ変換元Range要素も子Rangeならば、各要素(子Range)に対するstd::ranges::to結果からコンテナCを構築

  • 例:std::list<std::list<int>>からstd::vector<std::vector<double>>への一発変換など。

6. いずれの方式も利用不可ならばコンパイルエラー(ill-formed)

関連URL

*1:std::from_range はコンストラクオーバーロード選択(タグディスパッチ)用の定数。