Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

30 Nov 2020

C++20中的Ranges库

Ranges是C++20引入的一个库。其标准可以参考Ranges library。因为还很新,不是所有额编译器都提供,但是有开源的实现range-v3可以参考使用。

A beginner’s guide to C++ Ranges and Views这篇文章是很好的入门。如果你熟悉C++的各种形式的iterator的话,对于ranges也不会太陌生,它们都对序列进行操作。和Iterators不同的是,Ranges采用了C++ 20的最新特性Concepts,并且是惰性执行的。

下面是常见的range类型:

  • std::ranges::input_range,只可单次遍历的单向range
    • 比如 std::forward_list, std::list, std::deque, std::array
  • std::ranges::forward_range,可以多次遍历的单向range
    • 比如 std::forward_list, std::list, std::deque, std::array
  • std::ranges::bidirectional_range,双向range
    • 比如 std::list, std::deque, std::array
  • std::ranges::random_access_range,支持随机访问的range
    • 比如 std::deque, std::array
  • std::ranges::contiguous_range,内容上连续的range
    • std::array

此外还有size_range,output_range等等。

range的操作目标是各种container,但是操作的手段却是通过view这个类型来表达的。比如:

std::vector vec{1, 2, 3, 4, 5, 6};
auto v = std::views::reverse(vec);

多个view返回的结果可以串在一起:

std::vector vec{1, 2, 3, 4, 5, 6};
auto v = vec | std::views::reverse | std::views::drop(2);

前面提到ranges是惰性求值的。所以即便指定了view,只有真正获取元素的时候,view才会被执行。

C++20: The Ranges Library一文中列举了不同的view:

std::all_view, std::views::all               // takes all elements

std::ref_view                                // takes all elements of another view

std::filter_view, std::views::filter         // takes the elements which satisfies the predicate

std::transform_view, std::views::transform   // transforms each element

std::take_view, std::views::take             // takes the first N elements of another view

std::take_while_view, std::views::take_while // takes the elements of another view as long as the predicate returns true

std::drop_view, std::views::drop             // skips the first N elements of another view

std::drop_while_view, std::views::drop_while // skips the initial elements of another view until the predicate returns false

std::join_view, std::views::join             // joins a view of ranges

std::split_view, std::views::split           // splits a view by using a delimiter

std::common_view, std::views::common         // converts a view into a std::common_range

std::reverse_view, std::views::reverse       // iterates in reverse order

std::basic_istream_view, std::istream_view   // applies operator>> on the view

std::elements_view, std::views::elements     // creates a view on the N-th element of tuples

std::keys_view, std::views::keys             // creates a view on the first element of a pair-like values

std::values_view, std::views::values         // creates a view on the second elements of a pair-like values

C++ code samples before and after Ranges给出了一些代码上的示例。

VS 2019 16.8引入了不少ranges的特性。

其他参考