Ranges: Overview#
Ranges?#
Range: abstraction of “something that contains elements”
Inevitably a range must have
begin()
andend()
iterators ⟶ Range-based-forMost standard algorithms come with a range variant
Less error prone
More comfortable
Containers And Views (Storage Behavior)#
Containers are ranges that own their elements
Views do not own data
Refer to another range to draw elements from
Transformation done lazily during iteration/dereferencing
Example: std::views::drop
#
Dropping first two elements of a sequence, and printing the rest
⟶ no copy
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector numbers = {2, 1, 4, 3, 5};
auto first_two_dropped = std::views::drop(numbers, 2);
for (auto i: first_two_dropped)
std::cout << i << std::endl;
return 0;
}
$ ./c++11-ranges-drop-procedural
4
3
5
Example: std::views::take
#
Dropping first two, taking next two
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector numbers = {2, 1, 4, 3, 5};
auto first_two_dropped = std::views::drop(numbers, 2);
auto first_two_dropped_next_two_taken = std::views::take(first_two_dropped, 2);
for (auto i: first_two_dropped_next_two_taken)
std::cout << i << std::endl;
return 0;
}
$ ./c++11-ranges-drop-take-procedural
4
3
Pipe Syntax#
Syntactic sugar
Extremely readable
Example: dropping first two, taking next two
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
std::vector numbers = {2, 1, 4, 3, 5};
for (auto i: numbers | std::views::drop(2) | std::views::take(2))
std::cout << i << std::endl;
return 0;
}
$ ./c++11-ranges-drop-take-pipe
4
3
Views As Parameters: Good Old Template#
As an old-style template
#include <vector> #include <iostream> template <typename R> // <--- good ol' void print(const R& range) // function template { for (const auto& elem: range) std::cout << elem << std::endl; } int main() { std::vector numbers = { 1,2,3,4,5 }; print(numbers); return 0; }
Views As Parameters: Abbreviated Function Template#
This is new in C++20. The feature is inspired by generic lambda (new in C++14, and refined from then on; see here).
#include <vector>
#include <iostream>
void print(const auto& range) // <--- cool!
{
for (const auto& elem: range)
std::cout << elem << std::endl;
}
int main()
{
std::vector numbers = { 1,2,3,4,5 };
print(numbers);
return 0;
}
Views As Parameters: Concepts#
Abbreviated function templates are best combined with concepts
⟶ Better compiler errors
#include <vector>
#include <iostream>
void print(const std::ranges::input_range auto& range) // <--- not cool, but safe
{
for (const auto& elem: range)
std::cout << elem << std::endl;
}
int main()
{
std::vector numbers = { 1,2,3,4,5 };
print(numbers);
return 0;
}
Available <ranges>
Concepts#
Concept name |
Description |
---|---|
|
Can be iterated from beginning to end at least once |
|
Can be iterated from beginning to end multiple times |
|
Iterator can also move backwards with |
|
You can jump to elements in constant-time with |
|
Elements are always stored consecutively in memory |