Generic Types of Ranges
类型萃取从字面意思上来说其实就是帮助我们挑选某个对象的类型,筛选特定的对象来做特定的事。可以先来回顾一下以前的写法。- #include <vector>
- #include <iterator>
- int main() {
- std::vector v{1, 2, 3};
- using iterator_type = std::vector<int>::iterator;
- using difference_type = std::iterator_traits<iterator_type>::difference_type;
- using iterator_catogory = std::iterator_traits<iterator_type>::iterator_category;
- using pointer = std::iterator_traits<iterator_type>::pointer;
- using reference = std::iterator_traits<iterator_type>::reference;
- using value_type = std::iterator_traits<iterator_type>::value_type;
- }
复制代码 到了C++20,我们有了ranges,我们有了更多强大的工具,可以说它们是处理ranges的强大工具,我们来看看具体的内容。

通过上图,很多内容都直观明了,为了避免晦涩难懂的抽象话术,我们通过代码来看看具体用法。- #include <vector>
- #include <ranges>
- #include <algorithm>
- #include <iterator>
- #include <type_traits>
- int main() {
- std::vector v{10, 20, 30};
- static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::difference_type,
- std::iterator_traits<decltype(v)::iterator>::difference_type>); // OK
- static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::pointer,
- std::iterator_traits<decltype(v)::iterator>::pointer>); // OK
- static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::reference,
- std::iterator_traits<decltype(v)::iterator>::reference>); // OK
- static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::value_type,
- std::iterator_traits<decltype(v)::iterator>::value_type>); // OK
- static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::iterator_category,
- std::iterator_traits<decltype(v)::iterator>::iterator_category>); // OK
- // 可以明显看到,比起传统的迭代器萃取,C++20的处理方式更加简洁,只用传入ranges类型,而不用传入迭代器类型,或许这就是ranges的魅力所在。
-
- static_assert(std::is_same_v<std::ranges::sentinel_t<decltype(v)>,
- decltype(end(v))>); // OK
- // 获取哨兵类型。
- static_assert(std::is_same_v<std::ranges::range_reference_t<decltype(v)>,
- decltype(v[0])>); // OK, both are int&
- static_assert(std::is_same_v<std::ranges::range_reference_t<decltype(v)>,
- std::remove_reference_t<decltype(v[0])>>); // Error, int& and int
- static_assert(std::is_same_v<std::ranges::range_value_t<decltype(v)>,
- std::remove_reference_t<decltype(v[0])>>); // OK, both are int
- static_assert(std::is_same_v<std::ranges::range_value_t<decltype(v)>,
- decltype(v[0])>); // Error, int and int&
- static_assert(std::is_same_v<std::ranges::range_size_t<decltype(v)>,
- std::size_t>); // OK
- static_assert(std::is_same_v<std::ranges::range_difference_t<decltype(v)>,
- std::ptrdiff_t>); // OK
- static_assert(std::is_same_v<std::ranges::range_rvalue_reference_t<decltype(v)>,
- decltype(std::move(v[0]))>); // OK
- static_assert(std::is_same_v<std::ranges::borrowed_iterator_t<decltype(v)>,
- std::ranges::dangling>); // OK
- static_assert(std::is_same_v<std::ranges::borrowed_subrange_t<decltype(v)>,
- std::ranges::dangling>); // OK
- }
复制代码
Generic Types of Iterators
回到迭代器这一话题,为了更好的支持新的迭代器类型特征,你应该用如下的方式来代替传统的类型萃取。
 - #include <vector>
- #include <ranges>
- #include <type_traits>
- #include <iterator>
- int main() {
- std::vector v{1, 2, 3};
- using iterator_type = std::vector<int>::iterator;
- static_assert(std::is_same_v<std::iter_value_t<std::ranges::iterator_t<decltype(v)>>, int>);
- static_assert(std::is_same_v<std::iter_reference_t<std::ranges::iterator_t<decltype(v)>>, int&>);
- static_assert(std::is_same_v<std::iter_rvalue_reference_t<std::ranges::iterator_t<decltype(v)>>, int&&>);
- static_assert(std::is_same_v<std::iter_difference_t<std::ranges::iterator_t<decltype(v)>>, std::ptrdiff_t>);
- using type1 = std::common_reference_t<int, int>; // int
- using type2 = std::common_reference_t<int&, int>; // int
- using type3 = std::common_reference_t<int&, int&>; // int&
- using type4 = std::common_reference_t<int&, int&&>; // const int&
- using type5 = std::common_reference_t<int&&, int&&>; // int&&
- }
复制代码 common_reference_t过于复杂,暂且先跳过。可以看到,这也是萃取类型的一种方式,只不过写法不同罢了。话说回来,std::ranges::range_value_t其实就是std::iter_value_t的简化。
New Functional Types

std::identity是一个函数对象,返回对象本身,可以搭配ranges的算法一起使用。
[code]#include #include #include #include #include int main() { std::vector v{1, 2, 3}; auto pos = std::ranges::find(v, 9, [](auto x) { return x * x; }); if (pos != end(v)) std::cout |