Ranges之前和之后的C ++代码示例

你好 以下材料的翻译是专门为“ C ++开发人员”课程的学生准备的,该课程的课程将于6月27日开始。



去年11月在圣地亚哥举行的标准委员会会议上,C ++ 20采用了Ranges库。 该库提供用于处理旨在简化我们的代码的值范围的组件。 不幸的是,Ranges库没有很好的文档记录,这对于想要掌握它的人来说更难理解。 这篇文章旨在提供使用和不使用Ranges编写的代码示例。

此处提供 Eric Niebler的Ranges库实现。 它适用于Clang 3.6.2或更高版本,gcc 5.2或更高版本以及VC ++ 15.9或更高版本。 下面的代码示例已经使用最新版本的编译器进行编写和测试。 值得注意的是,这些示例是典型的实现,不一定是您可以想到的唯一解决方案。

尽管Ranges库的标准命名空间是std::ranges ,但在当前的库实现中,它是ranges::v3

以下示例中使用了以下名称空间别名:

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

另外,为简化起见,我们将引用以下对象,函数和lambda:

 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 :我要感谢Eric Nibler和下面其他评论的人,并为这些代码示例提供了建议。 我根据他们的评论更新了一些。

打印范围内的所有元素:

到范围响后
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); 


以相反的顺序打印范围的所有元素:

到范围响后
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); }; 


仅打印范围的偶数元素,但顺序相反:

到范围响后
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); }; 


跳过范围的前两个元素,仅打印以下三个元素中的偶数:

到范围响后
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); }; 


打印从101到200的数字:

到范围响后
C ++C ++
 for (int n = 101; n <= 200; ++n) { print_elem(n); } 
 for (auto n : rs::iota_view(101, 201)) { print_elem(n); } 


打印从101到200的所有罗马数字。要将数字转换为相应的罗马数字,请使用上面显示的to_roman()函数。

到范围响后
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); 


以相反的顺序打印在[101,200]范围内被7整除的最后三个数字的罗马数字。

到范围响后
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); } 


以相反的顺序创建一个字符串范围,该字符串包含后三个数字的罗马数字,它们是[101,200]范围中7的倍数。

到范围响后
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; 


更改未排序范围,使其仅保留唯一值,但顺序相反。

到范围响后
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; 


删除该范围的两个最小值和两个最大值,并将其余的顺序排列在第二个范围内。

到范围响后
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); 


将给定范围内的所有行合并为一个值。

到范围响后
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; 


计算文本中的单词数(以空格分隔)。

到范围响后
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(' ')); 


这篇文章对您有帮助吗? 在评论中写。

Source: https://habr.com/ru/post/zh-CN456452/


All Articles