6.view
view是一种range,它具有固定的拷贝、移动和赋值时间,正如名称所示,view是“视图”(引用),它本身不保存数据,因而可以保证复制等操作的等时间性。view一个重要的特征是“lazy evaluation”,即它在被定义的时候,仅将各种参数准备好,并没有运算,只有需要结果的时候,它才开始进行运算,得到结果。这个特性与数据库中的视图概念是一致的。
下面的示例说明了“lazy evaluation”的特性。
std::vector<int> ints{0,1,2,3,4,5,6};
auto res1= std::views::reverse(ints);
for(int i:res1) std::cout << i << ' ';
std::cout<<std::endl;
ints.push_back(7);
for(int i:res1) std::cout << i << ' ';
std::cout<<std::endl;
上面代码中,第一次输出6 5 4 3 2 1 0,第二次输出7 6 5 4 3 2 1 0,说明真正对vector ints的“reverse”操作(关于std::views::reverse见Range adaptor部分)发生在for语句中,而非在定义res1的时刻,ints变化了,view也跟着变化了,这也符合我们对“视图”的理解。
但正因如此,就像以前我们在枚举一个集合,不能同时对它进行修改一样,多个线程同时对container和view操作可能不会得到意料的结果。
7.range adaptor
range adaptor有点类似“加工器”(注意它本身不是range),输入的是可转化为view的range以及“加工方法”,输出的是view。比较有意思的是,管道操作符(|)被重载了,使得range adaptor可以“管道化”方式进行,如:
C(R) 等同于 R | C,C(R, args...) 等同于R | C(args…),其中C是Range adaptor,R是range,args是Range adaptor的输入参数,一般是一个“加工”函数。
标准库中已经定义了一些Range adaptor,如std::view::all,std::view::transform,std::view::filter,std::view::take等。以下是一个示例。
void test_range_view()
{
std: