C++20之Ranges
什么是ranges库
Ranges-v3库由Eric Niebler开发的,最初是作为N4128提案的基础,后来合并到C++20。
一个简单的示例
#include <ranges>
std::vector<double> vec{ 1.2, 1.3, 1.4, 3, 5 };
auto result = vec | std::views::filter([](double d) { return d > 1.2; })
| std::views::transform([](double d) { return d * 2; })
| std::views::take(2);
for (auto&& v : result) {
std::cout << v << " ";
}
// output: 2.6 2.8
其中result是一个复杂的view类型,其类型大致如下,编码过程中更建议使用auto进行声明,可读性更佳。
std::ranges::take_view<
std::ranges::transform_view<
std::ranges::filter_view<
std::ranges::ref_view<std::vector<double>>,
/* filter lambda 类型 */
>,
/* transform lambda 类型 */
>,
size_t
>
上述功能如果不适用ranges库,大致写法如下:
std::vector<double> nums{};
std::vector<double> filtered{};
std::copy_if(nums.begin(), nums.end(), std::back_inserter(filtered), pred);
std::vector<double> transformed{};
std::transform(...)...
ranges库解决的问题
- 传统STL算法需要迭代器和算法配合,读者一定写过不少begin + end的迭代器对,编码时很不友好;
- 避免中间容器,上述不使用
ranges库的代码中创建临时容器会有一定性能开销; - 惰性求值,
view只是一个惰性的试图,只有使用的时候才会计算,可以提高性能; - 函数式编程,
ranges提供的管道运算可以实现更直观的数据流,更加贴近函数式编程;
源码分析(MSVC)
前置知识concept
源码解读
#define _RANGES ::std::ranges::
_EXPORT_STD template <class _Ty>
concept view = range<_Ty> && movable<_Ty> && enable_view<_Ty>;
_EXPORT_STD template <class _Rng, class _Ty>
concept output_range = range<_Rng> && output_iterator<iterator_t<_Rng>, _Ty>;
_EXPORT_STD template <class _Rng>
concept forward_range = range<_Rng> && forward_iterator<iterator_t<_Rng>>;
_EXPORT_STD template <class _Rng>
concept random_access_range = range<_Rng> && random_access_iterator<iterator_t<_Rng>>;
_EXPORT_STD template <class _Rng>
concept range = requires(_Rng& __r) {
_RANGES begin(__r);
_RANGES end(__r);
};
Tags: #C++