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
Examples¶
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;
}
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;
}
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;
}
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 |