c++splitstd-rangesc++23string-view

Can `split_view` or a composition of multiple `spilt_view`s be used to split a `string`/`string_view` using multiple delimiters?


I'm attempting to understand how views can be composed and the limitations of the same. The idea here is to split a string/string_view without creating a temporary variable as shown in the second code block.

Why does the following not compile:

std::string line = "1[2]3";
for (const auto split : line 
                        | std::ranges::views::split('[') 
                        | std::ranges::views::transform([](const auto rng) {return std::string_view(rng); }) 
                        | std::ranges::views::split(']') 
                        | std::ranges::views::transform([](const auto rng) {return std::string_view(rng); })) {
    std::cout << split << '\n';
}

An additional question is why the above code fails to compile but the following work:

for (const auto split_once : line 
                             | std::ranges::views::split('[')
                             | std::ranges::views::transform([](const auto rng) {return std::string_view(rng); })) {
    for (const auto split_twice : split_once 
                                     | std::ranges::views::split(']') 
                                     | std::ranges::views::transform([](const auto rng) {return std::string_view(rng); })) {
            std::cout << split_twice << '\n';
   }
}

Link to compiler explorer


Solution

  • The first views::transform produces a range whose elements are of type string_view, which cannot be simply split by the character ']'.

    Instead, you can continue to split each single string_view and join them together, for example

    std::string line = "1[2]3";
    for (const auto split : line 
                            | std::ranges::views::split('[')
                            | std::ranges::views::transform(
                                std::ranges::views::split(']') |
                                std::ranges::views::transform(
                                  [](auto rng) {return std::string_view(rng); })
                              )
                            | std::views::join) {
        std::cout << split << '\n';
    }
    

    Demo