Quick reference for the Range-v3 library

Getting started

#include <iostream>
#include <range/v3/all.hpp>

int main(){
    // your code goes here
}

Practical examples can be found here or in the recently published manual which contains 27 fully-elaborated examples, 20 exercises with solutions, 5 online quizzes, 60 little drills and an extensive quick reference.

Range-v3

Range-v3 vs C++20 Ranges

views::zip_with was omitted from C++20 due to issues with proxy iterators and partial specializations (std::vector). Furthermore, some very useful views that can take care of cyclicity, grouping, striding, sliding etc. aren't part of C++20.

Range-v3

Nevertheless, there is a lot of hope for C++23 Ranges. You can find the plan here. In the Tier 1 of the C++23 Ranges implementation we expect the following views to be added from Range-v3:

  • views::group_by
  • views::for_each
  • views::sliding
  • views::zip
  • views::zip_with
  • views::enumerate
  • views::stride
  • views::chunk
  • views::cartesian_product

accumulate

Ex.1 Sum up elements of a range, starting from the value 0.0.

// (a -> b -> a) -> a -> [b] -> a
// foldl (+) 0.0 [1.5,2.7,3.8,4.2]
auto const v = std::vector<double> {1.5,2.7,3.8,4.2};
auto val = ranges::accumulate(v, 0.0); // 12.2

Ex.2 Fold elements of a range via multiplication, starting from the value 1.

// (a -> b -> a) -> a -> [b] -> a
// foldl (*) 1 [1,2,3,4]
auto const v = std::vector<int> {1,2,3,4};
auto val = ranges::accumulate(v, 1, [](int a, int b){return a * b;}); // 24

copy

C++20 Ranges

Ex.1 Copy a source range into a destination range.

std::vector<int> v {6,4,1,8,3};   
std::vector<int> v2;
ranges::copy(v, ranges::back_inserter(v2));
std::cout << ranges::views::all(v2); // [6,4,1,8,3]

Ex.2 Copy a source range into a destination range.

auto v = std::vector<int> {5,6,7,8,7};
auto v2 = ranges::copy(v);
std::cout << ranges::views::all(v2); // [5,6,7,8,7]

count

C++20 Ranges

Ex.1 Count the number of occurrences of the number 7.

auto const v = std::vector<int> {1,2,7,4,1,7};
auto val = ranges::count(v,7); // 2

distance

C++20 Ranges

Ex.1 Return the distance between the beginning and the end of the range.

auto const v1 = std::vector<char> {'a','b','c'};
auto const v2 = std::vector<char> {'c','d','e'};
auto v3 = ranges::views::set_union(v1,v2);
auto sz = ranges::distance(v3); // 5

equal

C++20 Ranges

Ex.1 Determine equality of two vectors.

// [1, 2, 3] == [3, 2, 1]
auto const v1 = std::vector<int> {1,2,3};
auto const v2 = std::vector<int> {3,2,1};   
auto val = ranges::equal(v1,v2); // false

Ex.2 Determine equality of two strings.

auto const s1 = std::string{"world"};
auto const s2 = std::string{"WORLD"};
auto val = ranges::equal(s1,s2); // false

find

C++20 Ranges

Ex.1 Find the first occurence of a specific value.

auto v = std::vector<int> {5,6,7,8,7};
auto it = ranges::find(v,7); 
assert(it  == v.begin() + 2);

for_each

C++20 Ranges

Ex.1 Print all the elements of a range.

auto const v = std::vector<int> {1,2,3,4};
ranges::for_each(v, [](int i){ std::cout << i  << " "; });

front

Ex.1 Retrieve the first element of a range.

auto v = std::vector<int> {5,6,7,8};
auto first = ranges::front(v); // 5

inner_product

Ex.1 Calculate the dot product of two vectors.

auto const v1 = std::vector<int> {1,3,-5};
auto const v2 = std::vector<int> {4,-2,-1};
auto val = ranges::inner_product(v1,v2,0); // 1*4 + 3*(-2) + (-5)*(-1) = 3

partition_copy

C++20 Ranges

Ex.1 Partition a vector into a vector of even and a vector of odd numbers.

std::vector<int> v {6,4,1,8,3};   
std::vector<int> even;
std::vector<int> odd;
 
ranges::partition_copy(v, ranges::back_inserter(even), 
                        ranges::back_inserter(odd), 
                        [] (int i) {return i % 2 == 0;});
    
std::cout << ranges::views::all(even) // [6,4,8]
          << ranges::views::all(odd); // [1,3]

Note: Currently it's not possible to use std::back_inserter with range-v3, as it's not default constructible, it does not satisfy the Iterator concept as defined by the range-v3 library.

sort

C++20 Ranges

Ex.1 Sort elements of a range in ascending order.

// Ord a => [a] -> [a]
// sort [6,7,1,3]
auto v = std::vector<int> {6,7,1,3};
ranges::sort(v); // [1,3,6,7]

Ex.2 Sort elements of a range in descending order.

// Ord a => [a] -> [a]
// sort [6,7,1,3]
auto v = std::vector<int> {6,7,1,3};
ranges::sort(v, std::greater{}; // [7,6,3,1]

Ex.3 Sort metals by their density.

struct Element {
   std::string name;
   double density;
   void print() const { std::cout << name << ' ' 
                                  << density << '\n'; }
};

int main() {      
    auto v = std::vector<Element> {{"Au", 19.3},{"Cu", 8.96},{"Ag", 10.5}};
    ranges::sort(v, std::less{}, &Element::density);
    ranges::for_each(v, &Element::print);
    /* Cu 8.96
       Ag 10.5
       Au 19.3 */
}

views::all

C++20 Ranges

Ex.1 Return a view containing all the elements of the source. Useful for converting STL containers to views.

// [a] -> [a]
auto const v = std::vector<int> {1,2,3,4,5};
auto rng = v | ranges::views::all; // [1,2,3,4,5]
std::cout << rng;

views::cartesian_product

C++23 Tier 1

Ex.1 Lazily create a cartesian product of two ranges.

auto letters = ranges::views::closed_iota('A','C');
auto numbers = ranges::views::closed_iota(1,2);	
    
auto rng = ranges::views::cartesian_product(letters, numbers);
for(auto[a,b] : rng)
    std::cout << a << ' ' << b << '\n';
// A 1
// A 2
// B 1
// B 2
// C 1
// C 2

views::chunk

C++23 Tier 1

Ex.1 Lazily divide a range into chunks of uniform size, e.g. 4-element chunks.

auto const v = std::vector<int> {1,2,3,4,5,6,7,8};
auto rng = v | ranges::views::chunk(4); // [[1,2,3,4],[5,6,7,8]]

views::common   

views::common is useful for mixing non-common ranges with old STL functions such as std::accumulate.

auto v = std::vector{8,7,3};
auto rng = v | views::take_while([](int x){return x > 5 ;})
             | views::common;
auto res = std::accumulate(rng.begin(),rng.end(),0); // 15

You will not need views::common for ranges::accumulate from Range-v3. You can read more about it here.

views::concat

Ex.1 Lazily concatenate ranges.

// [[a]] -> [a]
auto v1 = ranges::views::iota(3,6);
auto v2 = ranges::views::iota(7,9);
auto v3 = ranges::views::iota(11,14);
auto rng = ranges::views::concat(v1,v2,v3); // [3,4,5,7,8,11,12,13]

views::counted

C++20 Ranges

Ex.1 Lazily create a range that starts at the iterator begin + 1 and includes the next 2 elements.

auto v = std::vector<int> {6,7,8,9};
auto rng = ranges::views::counted(ranges::begin(v) + 1,2); // [7,8]

views::cycle

Ex.1 Lazily create a quasi-infinite circular range.

// [a] -> [a]
// cycle [1,3,9]
auto v = {1,3,9};
auto rng = v | ranges::views::cycle; // [1,3,9,1,3,9,1,3,9...]

views::delimit

Ex.1 Lazily delimit a range at the first occurrence of the value or at the end of the source range, whichever comes first.

auto v = {5,8,9,13,10,9};
auto rng = v | ranges::views::delimit(9); // [5,8]

views::drop

C++20 Ranges

Ex.1 Lazily drop the first two elements from the source range.

// Int -> [a] -> [a]
// drop 2 [4,9,3,1,7]
auto v = {4,9,3,1,7};
auto rng = v | ranges::views::drop(2); // [3,1,7]

views::drop_while

C++20 Ranges

Ex.1 Lazily remove all elements smaller than 5 from the front of a range.

auto v = {2,3,5,6,7};
auto rng = v | views::drop_while([](int x){return x < 5;}); // [5,6,7]

views::enumerate

C++23 Tier 1

Ex.1 Lazily pair elements of the source range with their index.

auto v = std::vector<std::string> {"apple", "banana", "kiwi"};
for (auto&& [first, second] : v | ranges::views::enumerate) {
        std::cout << first << ", " << second << '\n';
}
// 0, apple
// 1, banana
// 2, kiwi

views::exclusive_scan

Ex.1 Lazily accumulate elements of the source range starting from 0, excluding the last element.

auto const v = std::vector<int> {1,2,3,4};
auto rng = v | views::exclusive_scan(0); 
// [0,0+1,0+1+2,0+1+2+3]...[0,1,3,6]

Ex.2 Lazily accumulate elements of the source range starting from 10, excluding the last element.

auto const v = std::vector<int> {1,2,3,4};
auto rng = v | views::exclusive_scan(10);    
// [10,10+1,10+1+2,10+1+2+3]...[10,11,13,16]

views::filter  

C++20 Ranges

Range-v3 filter keep

Ex.1 Keep elements greater than 6.

auto v = {7,4,2,6,9};
auto rng = v | ranges::views::filter([](int x){return x > 6;}); // [7,9]

views::for_each

C++23 Tier 1

Ex.2 Lazily generate i+1 and i-1 for elements of a range and flatten the result (flatmap).

auto v = {1,10,100};
auto rng = ranges::views::for_each(v, [](int i){
    return ranges::views::linear_distribute(i-1,i+1,2);
}); // [0,2,9,11,99,101]

views::generate

Ex.1 Lazily create a range of positive even numbers going to infinity.

//    [2,4..]
auto rng = ranges::views::generate(
                [n = 1] () mutable { return 2*(n++); }); // [2,4,6,8...]

Ex.2 Lazily create a range of powers of two going to infinity.

// (a -> a) -> a -> [a]
// iterate (2*) 1
auto rng = ranges::views::generate(
                [n = 1] () mutable { return (n <<= 1) >> 1; }); // [1,2,4,8...]

views::group_by

C++23 Tier 1

Ex.1 Lazily group contiguous elements of a range together based on a binary predicate, e.g. odd and even.

// (a -> a -> Bool) -> [a] -> [[a]] 
auto v = std::vector<int> {7,4,2,6,9};
ranges::sort(v);
auto rng = v | ranges::views::group_by([](int x, int y) { 
                                        return x % 2 == y % 2; }); // [[2,4,6],[7,9]]

Ex.2 Lazily group identical letters of a string together. This is useful for frequency count.

auto s = std::string {"radar"};
ranges::sort(s);
auto rng = s | ranges::views::group_by([](char x, char y) { 
                                        return x == y; }); // [[a,a],[d],[r,r]]

views::intersperse

Ex.1 Lazily insert underscore between the letters of a string.

// a -> [a] -> [a]
auto const s = std::string {"London"};
auto s2 = s | ranges::views::intersperse('_')
            | to<std::string>(); // L_o_n_d_o_n

Ex.2 Lazily insert 0 between the numbers of a range.

// a -> [a] -> [a]
auto const v = std::vector<int> {1,2,3,4};
auto rng = v | ranges::views::intersperse(0); // [1,0,2,0,3,0,4]

views::iota

C++20 Ranges

Ex.1 Lazily create a range of integers [4,∞).

// [4..]
auto rng = ranges::views::iota(4); // [4,5,6,7...]

Ex.2 Lazily create a range of integers [8,9,10].

// [8..10]
auto rng = ranges::views::iota(8,11); // [8,9,10]

Ex.3 Lazily create a range of letters [A,B,C,D,E].

// ['A'..'E']
auto rng = ranges::views::iota('A','F'); // [A,B,C,D,E]

views::join

C++20 Ranges

Ex.1 Lazily flatten a range of ranges.

// [[a]] -> [a]
// concat [[1,3], [11,13,15], [25]]   
auto const v = std::vector<std::vector<int>>{
            {1,3},
            {11,13,15},
            {25},
};
auto rng = v | ranges::views::join; // [1,3,11,13,15,25]

views::keys

C++20 Ranges

Ex.1 Lazily retrieve keys of std::map.

auto const m = std::map<std::string, int> {{"London", 6}, {"New York", 7}};
auto rng = m | ranges::views::keys; // [London,New York]

views::linear_distribute

Ex.1 Lazily create a range of monotonically increasing values between 1.0 and 2.0 with a step 0.25.

auto rng = ranges::views::linear_distribute(1.0,2.0,5); // [1,1.25,1.5,1.75,2]

views::partial_sum

Ex.1 Lazily accumulate elements of the source range.

// [a] -> [a]
// scanl1 (+) [1,2,3,4]    
auto const v = std::vector<int> {1,2,3,4};
auto rng = v | ranges::views::partial_sum(std::plus{}}); // [1,3,6,10]

views::remove_if

Ex.1 Lazily discard even elements in the source range.

// (a -> Bool) -> [a] -> [a]
// filter odd [1,2,3,4,5]    
auto const v = std::vector<int>{1,2,3,4,5};
auto rng = v | ranges::views::remove_if(
                    [](int x){return x % 2 == 0;}); // [1,3,5]

views::repeat

Ex.1 Lazily create a range with all elements equal to 4.

// a -> [a]
// repeat 4
auto rng = ranges::views::repeat(4); // [4,4,4,4,4,4,4,..]

views::reverse

C++20 Ranges

Ex.1 Lazily reverse a range.

// [a] -> [a]
// reverse [1,2,3,4]
auto const v = std::vector<int> {1,2,3,4};
auto rng = v | ranges::views::reverse; // [4,3,2,1]

views::set_difference

Ex.1 Lazily calculate a difference of two input ranges.

// Eq a => [a] -> [a] -> [a]
// [3,4,5,6,7] \\ [4,5]
auto v1 = std::vector<int> {3,4,5,6,7}; // sort!
auto v2 = std::vector<int> {4,5}; // sort!
ranges::sort(v1); // sort!
ranges::sort(v2); // sort!
auto rng = ranges::views::set_difference(v1,v2); // [3,6,7]

views::set_intersection

Ex.1 Lazily calculate an intersection of two input ranges.

// Eq a => [a] -> [a] -> [a]
// intersect [3,4,5,6] [5,6,7,8] 
auto v1 = std::vector<int> {3,4,5,6};
auto v2 = std::vector<int> {5,6,7,8};
ranges::sort(v1); // sort!
ranges::sort(v2); // sort!
auto rng = ranges::views::set_intersection(v1,v2); // [5,6]

views::set_union

Ex.1 Lazily calculate a union of two input ranges.

// Eq a => [a] -> [a] -> [a]
// union [1,2,3] [4,5,6] 
auto const v1 = std::vector<int> {1,2,3};
auto const v2 = std::vector<int> {4,5,6};
auto rng = ranges::views::set_union(v1,v2); // [1,2,3,4,5,6]

views::single

C++20 Ranges

Ex.1 Lazily lift a value into a single-element range.

auto const rng = ranges::views::single(3); // [3]

Ex.2 Lazily lift a range into a range of ranges.

auto const v2 = ranges::views::single(ranges::views::iota(1,5)); // [[1,2,3,4]]

views::slice

Ex.1 Lazily create a slice that starts at the 2nd position (inclusively) and ends at the 4th position (exclusively) of the source range.

auto const v = std::vector<double> {1.1, 7.3, 14.5, 8.5, 17.6};
auto rng = v | ranges::views::slice(2,4); // [14.5,8.5]

views::sliding

C++23 Tier 1

Ex.1 Lazily create a sliding window of adjacent elements.

auto const v = std::vector<int> {1,2,3,4,5};
auto rng = v | views::sliding(2); // [[1,2],[2,3],[3,4],[4,5]]

views::split

C++20 Ranges

Ex.1 Lazily split a string at the whitespace.

auto const s = std::string{"hello world"};
auto rng = s | ranges::views::split(' ')
             | ranges::to<std::vector<std::string>>(); // materialization
// [hello,world]

views::stride

C++23 Tier 1

Ex.1 Lazily move to every third element of the range.

auto const v = std::vector<int>{0,1,2,3,4,5,6};
auto rng = v | ranges::views::stride(3); // [0,3,6]

views::tail

Ex.1 Lazily create a range without the first element of the source range.

// [a] -> [a]
// tail [1,2,3,4]
auto const v = std::vector<int> {1,2,3,4};
auto rng = v | ranges::views::tail; // [2,3,4]

views::take

C++20 Ranges

Ex.1 Lazily take the first three elements of a range.

// Int -> [a] -> [a]
// take 3 [1,2,3,4,5]
auto const v = std::vector<int> {1,2,3,4,5};
auto rng = v | ranges::views::take(3); // [1,2,3]

views::take_while

C++20 Ranges

Ex.1 Lazily take elements until the predicate fails.

// (a -> Bool) -> [a] -> [a]
auto const v = std::vectorr<int> {1,2,3,4};
auto rng1 = v | ranges::views::transform([](int x){return x*x;}); // [1,4,9,16]
auto rng2 = rng1 | ranges::views::take_while([](int x){return x < 10;}); // [1,4,9]

views::tokenize

Ex.1 Lazily break a string into distinct words.

auto const s = std::string{"Have a nice   day!"};
auto const rx = std::regex{"[\\w]+"}; 
auto rng = s | ranges::views::tokenize(rx);
std::cout << rng; // [Have,a,nice,day]

views::transform

C++20 Ranges

Ex.1 Lazily multiply elements of a range by 2.

// (a -> b) -> [a] -> [b]
// map (2*) [3,2,1] 
auto const v = std::vector<int> {3,2,1};
auto rng = v | ranges::views::transform(
                    [](int x){return 2*x;}); // [6,4,2]

views::unique

Ex.1 Lazily discard duplicates of neighbouring elements from a range.

// Eq a => [a] -> [a]
auto const v = std::vector<int> {1,2,2,3,1,1,2,2};
auto rng = v | ranges::views::unique; // [1,2,3,1,2]

views::values

C++20 Ranges

Ex.1 Lazily retrieve values from std::map.

auto const m = std::map<std::string, int> {{"London", 6}, {"New York", 7}};
auto rng = m | ranges::views::values; // [6,7]

views::zip   

C++23 Tier 1

Ex.1 Lazily match Arabic and Chinese numerals.

auto const v_ar = std::vector<int>{1,10,100,1000,10000};
auto const v_cn = std::vector<std::string>{"一","十","百","千","万"};
auto rng = ranges::views::zip(v_ar, v_cn);
for (auto&& [first, second] : rng) {
     std::cout << first << ", " << second << '\n';
}
/*  1, 一
    10, 十
    100, 百
    1000, 千
    10000, 万 */

views::zip_with

C++23 Tier 1

Ex.1 Lazily add two ranges.

// (a -> b -> c) -> [a] -> [b] -> [c]
// zipWith (+) [4,2,7] [3,2,1]
auto const v1 = std::vector<int> {4,2,7};
auto const v2 = std::vector<int> {3,2,1};
auto rng = ranges::views::zip_with(
                [](int a, int b){return a + b;}, v1, v2); // [7,4,8]

Tagged: Range-v3