📜 ⬆️ ⬇️

C ++ code examples before and after Ranges

Hello again. The translation of the following material has been prepared specifically for students of the “Developer C ++” course, which classes will start on June 27th.



The Ranges library was adopted in C ++ 20 at the Standard Committee meeting in San Diego last November. The library provides components for processing ranges of values ​​aimed at simplifying our code. Unfortunately, the Ranges library is not well documented, which makes it harder to understand for those who would like to master it. This post is intended to familiarize you with code examples written with and without Ranges.

An implementation of the Eric Niebler's Ranges library is available here . It works with Clang 3.6.2 or newer, gcc 5.2 or newer, and VC ++ 15.9 or newer. The code examples below were written and tested with the latest compilers. It is worth noting that these examples are typical implementations and are not necessarily the only solutions that can be devised.
')
Although the standard namespace for the Ranges library is std::ranges , in this current implementation of the library it ranges::v3 .

The following namespace aliases are used in the examples below:

 namespace rs = ranges::v3; namespace rv = ranges::v3::view; namespace ra = ranges::v3::action; 

Also, for simplicity, we will refer to the following objects, functions, and lambdas:

 std::string to_roman(int value) { std::vector<std::pair<int, char const*>> roman { { 1000, "M" },{ 900, "CM" }, { 500, "D" },{ 400, "CD" }, { 100, "C" },{ 90, "XC" }, { 50, "L" },{ 40, "XL" }, { 10, "X" },{ 9, "IX" }, { 5, "V" },{ 4, "IV" }, { 1, "I" } }; std::string result; for (auto const & [d, r]: roman) { while (value >= d) { result += r; value -= d; } } return result; } std::vector<int> v{1,1,2,3,5,8,13,21,34}; auto print_elem = [](auto const e) {std::cout << e << '\n'; }; auto is_even = [](auto const i) {return i % 2 == 0; }; 

APDATE : I would like to thank Eric Niebler and all the others who commented below with suggestions for these code examples. I updated a few based on their feedback.

Print all elements of the range:

To rangesAfter ranges
C ++C ++
 std::for_each( std::cbegin(v), std::cend(v), print_elem); // or for(auto const i : v) { print_elem(i); }; 
 rs::for_each( std::cbegin(v), std::cend(v), print_elem); // or rs::for_each(std::as_const(v), print_elem); 


Output all elements of the range in the reverse order:

To rangesAfter ranges
C ++C ++
 std::for_each( std::crbegin(v), std::crend(v), print_elem); 
 rs::for_each( std::crbegin(v), std::crend(v), print_elem); // or for (auto const i : v | rv::reverse) { print_elem(i); }; 


Print only even elements of the range, but in reverse order:

To rangesAfter ranges
C ++C ++
 std::for_each( std::crbegin(v), std::crend(v), [print_elem](auto const i) { if(i % 2 == 0) print_elem(i); }); 
 for (auto const i : v | rv::reverse | rv::filter(is_even)) { print_elem(i); }; 


Skip the first two elements of the range and output only even of the following three:

To rangesAfter ranges
C ++C ++
 auto it = std::cbegin(v); std::advance(it, 2); auto ix = 0; while (it != std::cend(v) && ix++ < 3) { if (is_even(*it)) print_elem(*it); it++; } 
 for (auto const i : v | rv::drop(2) | rv::take(3) | rv::filter(is_even)) { print_elem(i); }; 


Print the numbers from 101 to 200:

To rangesAfter ranges
C ++C ++
 for (int n = 101; n <= 200; ++n) { print_elem(n); } 
 for (auto n : rs::iota_view(101, 201)) { print_elem(n); } 


Output all Roman numerals from 101 to 200. To convert a number to the corresponding Roman number, use the function to_roman() shown above.

To rangesAfter ranges
C ++C ++
 for (int i = 101; i <= 200; ++i) { print_elem(to_roman(i)); } 
 for (auto n : rs::iota_view(101, 201) | rv::transform(to_roman)) { print_elem(n); } // or rs::for_each(rv::iota(101, 201), print_element, to_roman); 


Print the Roman numerals of the last three numbers, divisible by 7 in the [101, 200] range, in reverse order.

To rangesAfter ranges
C ++C ++
 for (int n = 200, count=0; n >= 101 && count < 3; --n) { if (n % 7 == 0) { print_elem(to_roman(n)); count++; } } 
 for (auto n : rs::iota_view(101, 201) | rv::reverse | rv::filter([](auto v) { return v % 7 == 0; }) | rv::transform(to_roman) | rv::take(3)) { print_elem(n); } 


Create a string range containing the roman numerals of the last three numbers that are a multiple of 7 in the [101, 200] range, in the reverse order.

To rangesAfter ranges
C ++C ++
 std::vector<std::string> v; for (int n = 200, count = 0; n >= 101 && count < 3; --n) { if (n % 7 == 0) { v.push_back(to_roman(n)); count++; } } 
 auto v = rs::iota_view(101, 201) | rv::reverse | rv::filter([](auto v) {return v % 7 == 0; }) | rv::transform(to_roman) | rv::take(3) | rs::to_vector; 


Modify the unsorted range so that it retains only unique values, but in reverse order.

To rangesAfter ranges
C ++C ++
 std::vector<int> v{ 21, 1, 3, 8, 13, 1, 5, 2 }; std::sort(std::begin(v), std::end(v)); v.erase( std::unique(std::begin(v), std::end(v)), std::end(v)); std::reverse(std::begin(v), std::end(v)); 
 std::vector<int> v{ 21, 1, 3, 8, 13, 1, 5, 2 }; v = std::move(v) | ra::sort | ra::unique | ra::reverse; 


Remove the two smallest and two largest range values ​​and leave the rest, ordered in the second range.

To rangesAfter ranges
C ++C ++
 std::vector<int> v{ 21, 1, 3, 8, 13, 1, 5, 2 }; std::vector<int> v2 = v; std::sort(std::begin(v2), std::end(v2)); auto first = std::begin(v2); std::advance(first, 2); auto last = first; std::advance(last, std::size(v2) - 4); v2.erase(last, std::end(v2)); v2.erase(std::begin(v2), first); 
 std::vector<int> v{ 21, 1, 3, 8, 13, 1, 5, 2 }; auto v2 = v | rs::copy | ra::sort | ra::slice(2, rs::end - 2); 


Combine all rows in this range into one value.

To rangesAfter ranges
C ++C ++
 std::vector<std::string> words { "Lorem", " ", "ipsum", " ", "dolor", " ", "sit", " ", "amet"}; std::string text; for (auto const & word : words) text += word; 
 std::vector<std::string> words { "Lorem", " ", "ipsum", " ", "dolor", " ", "sit", " ", "amet"}; std::string text = words | rs::move | ra::join; 


Count the number of words (separated by a space) in the text.

To rangesAfter ranges
C ++C ++
 auto text = "Lorem ipsum dolor sit amet"; std::istringstream iss(text); std::vector<std::string> words( std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>()); auto count = words.size(); // or size_t count = 0; std::vector<std::string> words; std::string token; std::istringstream tokenStream(text); while (std::getline(tokenStream, token, ' ')) { ++count; } 
 auto text = "Lorem ipsum dolor sit amet"; auto count = rs::distance( rv::c_str(text) | rv::split(' ')); 


Was the article helpful to you? Write in the comments.

Source: https://habr.com/ru/post/456452/


All Articles