C++ 20 Range

简单理解为:封装了begin(),end()这一对迭代器的对象。range的抽象级别更高,具有更多好处。
1)避免繁琐

std::for_each( begin(v), end(v),  //迭代器,书写繁琐,易错
    []( auto i ){ std::cout << i ; } 
) ;

std::ranges::for_each( v,    //range写法
    []( auto i ){ std::cout << i ; }
) ;

2)函数式编程

for ( auto i : iota( 1, 10 ) | reverse )  //描述目的
    std::cout << i ;

for ( auto i = 10 ; i>0 ; --i )  //描述算法步骤
    std::cout << i ;
#include <algorithm>
#include <iostream>
#include <vector>
 
int main()
{
   std::vector<int> numbers = { 1, 2, 3 ,4, 5 };
 
   std::vector<int> evenNumbers;
   std::copy_if(begin(numbers), end(numbers), 
         std::back_inserter(evenNumbers), [](int n){ return n % 2 == 0; });
 
   std::vector<int> results;
   std::transform(begin(evenNumbers), end(evenNumbers), 
         std::back_inserter(results), [](int n){ return n * 2; });
 
   for (int n : results)
   {
      std::cout << n << ' ';
   }
}

STL算法的缺点:各自为政,粘合在一起的代价大。现在用range重写:

std::vector<int> numbers={1,2,3,4,5};
auto v = numbers | ranges::view::filter([](int n){ return n % 2 == 0; })
                 | ranges::view::transform([](int n) { return n * 2; });
for(auto i : v) std::cout << i ;

管道符|方式的等价物是C语言方式:

std::vector<int> numbers={1,2,3,4,5};

filter_view f( numbers, [](int n){ return n % 2 == 0; } ) ;
transform_view t( f, [](int n) { return n * 2; } ) ;

for ( auto n : t )
    std::cout << n ;

Range库提供很多算法,能代替STL。下文代码片段统一需要:

#include <vector>
#include <list>
#include <map>
#include <iostream>
#include <string> 
#include <range/v3/all.hpp>
int main()
{    
    auto concat = [](std::string a, int b){ 
                      return std::move(a) + '-' + std::to_string(b); 
                  };

    auto const v = std::vector<int> {1,2,3,4,5};
    
    //累积{1,2,3,4,5},变成1-2-3-4-5
    auto rng = ranges::accumulate(v | ranges::views::drop(1), std::to_string(v[0]), concat);
    
    //等价的“手写”代码
    std::string result = std::to_string(v[0]);
    for(auto ite = std::next(v.begin()); ite!=v.end(); ++ite){
        result = concat(result,*ite );
    }
    std::cout << result ;
}
int main()
{    
    std::vector<int> v {6,4,1,8,3};  
    //copy vector到cout的经典代码 
    ranges::copy(v, ranges::ostream_iterator<>(std::cout, " "));

    std::vector<int> v2;
    ranges::copy(v, ranges::back_inserter(v2));
}
int main()
{    
    auto v = std::vector<int> {6,7,1,3};
    std::vector<int> result = ranges::sort(v); // [1,3,6,7] 
}
int main()
{    
    auto const v = std::vector<int> {1,2,3,4,5};
    //把实体view化
    auto rng = v | ranges::views::all; // [1,2,3,4,5]
    std::cout << rng ;  //std::vector是不能与cout结合的,但是view可以
    //std::cout << ranges::views::all(v);
}
int main()
{    
    auto const cities = std::vector<std::string>  {"New York", "Moscow", "Berlin", "Beijing" };
    auto const population = std::vector<double>   { 8.6,        11.9,     3.5                };
    auto const country = std::vector<std::string> {"US",       "RU",      "DE"               };
    
    //zip操作
    auto rng = ranges::views::zip(cities, population, country);

    //结构化绑定
    for (auto&& [first, second, third] : rng) 
         std::cout << first << ", " << second << "," << third << '\n';
}
int main()
{    
    auto const v = std::map<int,char>{ {1,'A'},{2,'B'},{3,'C'},{4,'D'},{5,'E'} };

    //通用的元素删除
    auto rng = v | ranges::views::remove_if( [](auto p) { return p.first%2==0; } );
    
    for (auto[k,v]:rng){ std::cout << k << " " << v << std::endl; }
}
int main()
{    
    std::string s1 = "hello ";
    std::string s2 = "world!";
    
    //concat是操作多个独立的range对象
    auto rng = ranges::views::concat(s1,s2); 
    std::cout << rng << std::endl;

    auto const v = std::vector<std::vector<int>>{ {1,3}, {11,13,15}, {25},};
    
    //join操作的是一个range,这个range的元素是range(简称range的range)
    auto rng2 = v | ranges::views::join; // [1,3,11,13,15,25]
    std::cout << rng2 << std::endl;
}
int main()
{    
    std::string sentence = "hello world!";
    auto rng = sentence | ranges::views::split(' ') | ranges::to<std::list<std::string>>; 
    for (auto str : rng){
        std::cout << str << std::endl;
    }
}

最后这个split view,需要物化后才能直接遍历,这是很多初次接触到split适配器的人忽视的地方。
参考:https://www.walletfox.com/course/quickref_range_v3.php

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值