Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

C++ Ranges

C++ Ranges is a powerful library feature introduced in C++20 that revolutionizes how developers work with collections of data. The concept of ranges has deep roots in functional programming and was implemented in C++ through a long evolution starting with the Boost Range library and later Eric Niebler's range-v3 library, which served as the prototype for the standardized version. Ranges represent a sequence of elements that can be traversed, viewed through different lenses, and manipulated through a chain of operations. The key innovation of ranges is that they allow algorithm operations to be composed using the pipe operator (|), similar to Unix command pipelines, which makes for more readable and maintainable code compared to traditional iterator-based approaches.

Ranges address several critical problems in modern C++ development. They significantly reduce the verbosity of collection processing by eliminating the need to explicitly manage iterators or temporary containers. They enable lazy evaluation, meaning that operations are only applied when needed, which improves performance for large datasets or complex transformations. Ranges make code more declarative rather than imperative, allowing developers to focus on what they want to achieve rather than how to achieve it. Additionally, ranges are composable, allowing multiple operations to be chained together in a clear, concise manner without the nesting complexity that occurs with traditional algorithm usage.

Core Components

Views

Views are lightweight range adaptors that transform or filter a sequence without modifying the underlying collection:

  • std::views::filter: Creates a view that includes only elements that satisfy a predicate
  • std::views::transform: Applies a function to each element in a range
  • std::views::take: Takes the first N elements of a range
  • std::views::drop: Skips the first N elements of a range
  • std::views::reverse: Reverses the order of elements in a range
  • std::views::elements: Extracts specific elements from a range of tuples or similar structures

Range Algorithms

C++20 provides ranged versions of most standard algorithms:

  • std::ranges::find, std::ranges::find_if
  • std::ranges::sort, std::ranges::stable_sort
  • std::ranges::for_each
  • And many more

Examples

Basic Filtering and Transformation

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// Filter for even numbers and square them
auto result = numbers 
    | std::views::filter([](int n) { return n % 2 == 0; })
    | std::views::transform([](int n) { return n * n; });

// Print: 4, 16, 36, 64, 100
for (int n : result) {
    std::cout << n << " ";
}

Combining with Algorithms

std::vector<std::string> words = {"apple", "banana", "cherry", "date", "elderberry"};

// Find the first word starting with 'c'
auto it = std::ranges::find_if(words, [](const std::string& s) {
    return !s.empty() && s[0] == 'c';
});

if (it != words.end()) {
    std::cout << "Found: " << *it << '\n';
}

Good Practices

  1. Prefer ranges and views when working with collections for better readability and maintainability
  2. Use range composition to eliminate intermediate containers
  3. Remember that views are lazy - they don't perform operations until needed
  4. Use range-based for loops with views for simple iteration

Potential Pitfalls

  1. Complex view chains can be harder to debug than explicit iteration
  2. Range views may have different performance characteristics than equivalent hand-written loops
  3. Some views in C++20 have limitations that are addressed in C++23

Further Reading

License

This code is provided under the MIT License. Feel free to use, modify, and distribute as needed.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.