Using std::views::split in C++ with Delimiters

In modern C++, std::views::split is a range adaptor that divides an underlying view into a sequence of subranges using a specified pattern or delimiter. This article explains how std::views::split detects delimiters, handles lazy evaluation, produces subranges without memory allocation, and processes both single-element and multi-element patterns.

How std::views::split Works

Introduced in C++20 and refined in C++23, std::views::split operates as a range adaptor closure object found in the <ranges> header. It takes two primary components: an underlying range to be split and a delimiter pattern.

The delimiter can be a single element (such as a character ' ') or a forward range (such as a string literal " - " or another subview). When applied, std::views::split creates a lazy view over the original data. Instead of allocating memory or generating a container of tokens immediately, it computes token boundaries on demand as iterators advance.

Dividing Views by Pattern

When traversing the input view, std::views::split searches for matches against the delimiter pattern:

  1. Pattern Matching: It scans the source sequence using an algorithm conceptually equivalent to std::search. If the delimiter is a sequence of multiple elements, std::views::split ensures the exact contiguous sequence matches before breaking the range.
  2. Subrange Production: Each element yielded by iterating through the split view is itself a subrange (std::ranges::subrange). This subrange references the elements in the original view that sit between two matching delimiters (or between the boundary and a delimiter).
  3. Delimiter Skipping: The matching delimiter elements are omitted from the yielded subranges. Once a match is found, the start of the next subrange is positioned immediately after the delimiter.

Code Example

The following example demonstrates splitting a string using a multi-character delimiter pattern:

#include <iostream>
#include <ranges>
#include <string_view>

int main() {
    std::string_view text = "Apple-->Banana-->Orange-->Grape";
    std::string_view delimiter = "-->";

    // Split the view using a multi-character pattern
    auto tokens = text | std::views::split(delimiter);

    for (auto token : tokens) {
        // Construct a string_view from the subrange to print cleanly
        std::cout << std::string_view(token) << '\n';
    }

    return 0;
}

Output:

Apple
Banana
Orange
Grape

Key Behaviors and Nuances

  • Empty Subranges: If two delimiters appear consecutively, or if the source range begins or ends with a delimiter, std::views::split produces empty subranges at those locations.
  • Zero Allocations: Because it produces views rather than instantiating copies, std::views::split causes zero heap allocations. It operates safely over non-owning views such as std::string_view or std::span.
  • C++20 vs. C++23 Evolution: In C++20, std::views::split produced inner subranges with an iterator type that could not easily be converted into standard standard string views. C++23 redesigned std::views::split so that the inner ranges model std::ranges::forward_range when possible, moving the original C++20 forward-range-agnostic implementation to std::views::lazy_split.