Advancing from abstract ranges to the ranges library
We have used the term range many times in the previous chapter. A range is an abstraction of a sequence of elements, delimited by two iterators (one to the first element of the sequence, and one to the one-past-the-last element). Containers such as std::vector, std::list, and std::map are concrete implementations of the range abstraction. They have ownership of the elements and they are implemented using various data structures, such as arrays, linked-lists, or trees. The standard algorithms are generic. They are container-agnostic. They know nothing about std::vector, std::list, or std::map. They handle range abstractions with the help of iterators. However, this has a shortcoming: we always need to retrieve a beginning and end iterator from a container. Here are some examples:
// sorts a vector
std::vector<int> v{ 1, 5, 3, 2, 4 };
std::sort(v.begin(), v.end());
// counts even numbers in an array
std::array<int, 5>...