DEV Community

Cover image for Getting Started with C++20 Ranges: Write Cleaner and Safer Loops
Official Beep8
Official Beep8

Posted on

Getting Started with C++20 Ranges: Write Cleaner and Safer Loops

Getting Started with C++20 Ranges: Write Cleaner and Safer Loops

If you've ever written a loop that filters, transforms, or slices a collection manually, you know how verbose and error-prone it can get.

C++20 introduces the <ranges> library, which allows you to express these operations clearly and safely, using a declarative and composable style.

In this article, we'll walk through the essentials of C++20 ranges — focusing on real-world use cases that will make your code shorter, safer, and more readable.


✅ What Are Ranges?

At a high level, ranges combine the container and the algorithm into a single, chainable expression.

Instead of writing this:

std::vector<int> result;
for (int x : input) {
    if (x % 2 == 0) {
        result.push_back(x * x);
    }
}
Enter fullscreen mode Exit fullscreen mode

You can now write:

auto result = input 
    | std::views::filter([](int x) { return x % 2 == 0; })
    | std::views::transform([](int x) { return x * x; });
Enter fullscreen mode Exit fullscreen mode

This is concise, expressive, and lazy-evaluated, meaning no unnecessary copies unless you actually use the results.


✅ Basic Setup

To use ranges, include:

#include <ranges>
#include <vector>
#include <iostream>
Enter fullscreen mode Exit fullscreen mode

Make sure your compiler supports C++20. For GCC or Clang, you may need to pass -std=c++20.


✅ Practical Example: Filtering Even Numbers

std::vector<int> data = {1, 2, 3, 4, 5, 6};

auto evens = data 
    | std::views::filter([](int x) { return x % 2 == 0; });

for (int x : evens) {
    std::cout << x << " ";
}
// Output: 2 4 6
Enter fullscreen mode Exit fullscreen mode

No need to write an explicit if in the loop — just describe what you want.


✅ Transforming Values: Square Each Number

auto squares = data 
    | std::views::transform([](int x) { return x * x; });

for (int x : squares) {
    std::cout << x << " ";
}
// Output: 1 4 9 16 25 36
Enter fullscreen mode Exit fullscreen mode

Perfect for applying a function to every element.


✅ Combining Views: Filter and Then Transform

Here's where ranges shine — chaining multiple views:

auto even_squares = data
    | std::views::filter([](int x) { return x % 2 == 0; })
    | std::views::transform([](int x) { return x * x; });

for (int x : even_squares) {
    std::cout << x << " ";
}
// Output: 4 16 36
Enter fullscreen mode Exit fullscreen mode

This kind of code used to take 5+ lines and intermediate containers — now it's just one pipeline.


✅ Taking and Dropping Elements

You can slice ranges without dealing with iterators:

auto first_three = data 
    | std::views::take(3);

for (int x : first_three) {
    std::cout << x << " ";
}
// Output: 1 2 3
Enter fullscreen mode Exit fullscreen mode

Likewise:

auto skip_two = data 
    | std::views::drop(2);

for (int x : skip_two) {
    std::cout << x << " ";
}
// Output: 3 4 5 6
Enter fullscreen mode Exit fullscreen mode

No begin() + n needed!


✅ Converting Views to Containers

Views are lazy — they don’t create new containers unless you explicitly request one:

std::vector<int> result(
    even_squares.begin(), even_squares.end()
);
Enter fullscreen mode Exit fullscreen mode

Alternatively, use a helper library like range-v3 or std::ranges::to in C++23.


✅ Why Should You Use Ranges?

✅ Removes boilerplate loops

✅ Avoids intermediate containers

✅ Makes intent clearer

✅ Encourages functional composition

✅ More type-safe than raw iterators


⚠️ Gotchas

  • Views don’t own data — if the original container goes out of scope, the view becomes invalid.
  • Not all STL algorithms are ranges-enabled yet (std::ranges::sort, etc. is available though).
  • May have compilation issues on older compilers or incomplete standard libraries.

Final Thoughts

C++20 ranges bring modern, declarative iteration to C++.

If you've ever felt envious of LINQ in C#, or Python list comprehensions — this is your new best friend in C++.


✍️ Summary

  • std::views::filter, transform, take, drop are your new loop tools
  • Ranges let you focus on what to do, not how
  • Safer, more elegant, and often faster than manual loops

Have you tried ranges in your own codebase yet? Let me know how it changed your workflow — or what hurdles you're running into.


Follow me for more modern C++ tips — and feel free to share your favorite ranges trick in the comments!

Top comments (0)