yohhoyの日記

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

std::views::splitで文字列分割

C++2a(C++20) Rangesライブラリstd::views::splitを利用した文字列分割処理。*1
2021-06-24追記:次期C++2b(C++23)標準ライブラリではよりシンプルな実装が可能となる。

split2str関数は「char範囲を区切り文字delimで分割しstd::stringのViewへ変換するレンジアダプタ(range adaptor)」を返す。

// C++2a(C++20)
#include <iomanip>
#include <iostream>
#include <string>
#include <string_view>
#include <ranges>

auto split2str(char delim) {
  return std::views::split(std::views::single(delim))
       | std::views::transform([](auto v) {
           auto cv = v | std::views::common;
           return std::string{cv.begin(), cv.end()};
         });
}

int main() {
  std::string_view s = "apple,banana,cinnamon";
  for (const auto& word : s | split2str(',')) {
    std::cout << std::quoted(word) << "\n";
  }
}
// "apple"
// "banana"
// "cinnamon"

ノート:std::views::splitは区切り要素(char)ではなく “区切りパターン(range)” を引数にとるため、std::views::single(delim)のように単一要素レンジを明示する必要がある雰囲気。splitに左辺値delimを指定すると意図通りに動作せず、キャストによりchar型右辺値を与えるとなぜか動く。C++2a Rangesライブラリは処理系任せの部分が大きく、トラブル時の振る舞いを説明しづらい。単に理解不足かorz

  • 2021-06-23追記:GCC HEAD 12.0.0 20210621(experimental)で再確認したところ、単にstd::views::split(delim) | ...と記述しても期待通りに動作した。

C++2a DIS(N4861) 24.7/p1, 24.7.1/p1より引用。

This subclause defines range adaptors, which are utilities that transform a range into a view with custom behaviors. These adaptors can be chained to create pipelines of range transformations that evaluate lazily as the resulting view is iterated.

A range adaptor closure object is a unary function object that accepts a viewable_range argument and returns a view. For a range adaptor closure object C and an expression R such that decltype((R)) models viewable_range, the following expressions are equivalent and yield a view:

C(R)
R | C

Given an additional range adaptor closure object D, the expression C | D is well-formed and produces another range adaptor closure object such that the following two expressions are equivalent:

R | C | D
R | (C | D)

関連URL

*1:厳密には std::ranges::views::split として宣言される。標準ヘッダ<ranges>にてstd名前空間以下で namespace views = ranges::views; と名前空間エイリアスが定義されている。