c++的库函数有哪些 C++范围库应用 视图与管道操作指南
C 范围库中的视图和管道操作通过声明式、惰性效率高效求值的方式简化序列数据处理,支持组合转换操作,避免数据复制,可自定义视图并与其他算法良好使用,提升代码有效性与性能。
C范围库,尤其是视图和管道操作,大大简化了处理序列数据的代码。它们允许你以式说明的方式组合数据转换,从而创建显着地编写循环或临时集合。本质上,它们是懒惰的,只在需要时才计算结果。
视图和管道操作是C 20引入的范围库的核心组成部分,它们提供了一种高效且丰富表现力的方式来处理序列数据。下面是使用视图和管道操作的指南。什么是C 范围库中的视图?
视图(Views)是范围库的一个关键概念。它们本质上是数据的“窗口”,提供对底层数据的重复或可访问,而无需复制数据。这意味着视图操作通常非常快,因为它们避免了了不需要的内存分配和数据复制。视图可以组合和转换,以创建复杂的数据处理模拟。例如,您可以创建一个视图来过滤一个序列,然后将结果映射到另一个值序列。如何使用管道操作组合视图?
管道操作符|登录后复制登录后复制用于将多个视图组合在一起,形成一个数据处理管道。每个视图都会对输入数据进行转换,并将结果传递给下一个视图。这种方式使代码更易读、更容易理解,也更容易维护。
立即学习“C免费学习笔记(深入)”;
例如,假设你有一个整数连接,你想过滤所有偶数,然后将剩下的每个数去掉。使用范围库,你可以这样写:#include lt;iostreamgt;#include lt;vectorgt;#include lt;rangesgt;#include lt;algorithmgt;int main() { std::vectorlt;intgt; numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto results = numbers | std::views::filter([](int n){ return n 2 != 0; }) | std::views::transform([](int n){ return n * n; }); for (int result : results) { std::cout lt;lt; result lt;lt; quot; quot;; // 输出: 1 9 25 49 81 } std::cout lt;lt; std::endl; return 0;}登录后复制
be代码首先创建了一个包含整数的复制。,它使用管道操作符|登录后复制登录后复制然后将两个视图组合在一起:std::视图::filter登录后复制登录后复制和std::views::transform登录后复制登录后复制登录后复制。std::views::filter登录后复制登录后复制将视图过滤掉所有偶数,而std::观看次数::转换登录后复制登录后复制登录后复制视图将剩余的每平方。最终,结果被存储在结果登录后复制 变量中,您可以像遍历任何其他序列一样遍历它。
如何自定义视图?
虽然标准库提供了许多有用的视图,但有时你需要创建自己的视图来满足特定的需求。你可以通过继承std::ranges::view_interface登录后复制类来创建自定义视图。
例如,假设你想创建一个视图,它只返回序列中的前N个元素。你可以这样写:#include lt;iostreamgt;#include lt;vectorgt;#include lt;rangesgt;template lt;typename Rangegt;class take_view : public std::ranges::view_interfacelt;take_viewlt;Rangegt;gt; {private: Range base_; size_t count_;public: take_view() = default; take_view(Range base, size_t count) : base_(std::move(base)), count_(count) {} auto begin() { return std::范围::begin(base_); } auto end() { auto it = std::ranges::begin(base_); std::advance(it, std::min(count_, std::ranges::size(base_))); return it; }};template lt;typename Rangegt;take_view(Rangeamp;amp;, size_t) -gt; take_viewlt;std::ranges::views::all_tlt;Rangegt;gt;;命名空间 my_views { inline constexpr auto take = [] (size_t count) { return std::ranges::views::transform([count](autoamp;amp; range) { return take_view(std::forwardlt;decltype(range)gt;(range), count); }); };}int main() { std::vectorlt;intgt; numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};自动结果 = 数字 | my_views::take(5); for (int result : results) { std::cout lt;lt; result lt;lt; quot; quot;; // 输出: 1 2 3 4 5 } std::cout lt;lt; std::endl; return 0;}登录后复制
这个例子定义了一个名为take_view登录后复制登录后复制的习惯观点,它接受一个范围和一个统计数据作为参数。
begin()登录后复制和end()登录后复制登录后复制方法返回范围的开始结束和复制器,但end()登录后复制登录后复制复制器被调整为指向范围中的第计数登录后复制个元素。my_views::take登录后复制是一个视图生成器,它接受一个计数并返回一个可评估范围的闭包,以创建take_view登录后复制登录后复制范围库的性能考量
虽然视图通常非常高效,但重要的是要了解它们的性能特征。由于视图是懒惰的,它们只需要时才计算结果。这意味着如果你不浏览整个视图,那么一些计算可能永远不会发生。然而,也意味着每次你访问视图中的一个元素时,都需要重新计算该元素。在某些情况下,这可能会导致性能问题。
考虑以下示例:#include lt;iostreamgt;#include lt;vectorgt;#include lt;rangesgt;#include lt;chronogt;int main() { std::vectorlt;intgt; numbers(1000000); std::generate(numbers.begin(), numbers.end(), [](){ return rand() 100; }); auto start = std::chrono::high_resolution_clock::now(); auto results = numbers | std::views::filter([](int n){ return n gt; 50; }) | std::views::transform([](int n){ std::this_thread::sleep_for(std::chrono::microseconds(1)); // 模拟运行操作 return n * n; }); // 只访问前10个元素 for (int i = 0; i lt; 10; i) { std::cout lt;lt; *std::next(results.begin(), i) lt;lt; quot; quot;; } std::cout lt;lt; std::endl; auto end = std::chrono::high_resolution_clock::now(); auto period = std::chrono::duration_castlt;std::chrono::millisecondsgt;(end - start); std::cout lt;lt; quot;持续时间: quot; lt;lt;duration.count() lt;lt;quot;msquot;lt;lt;由于std::endl;return 0;}登录后复制
在这个例子中,std::views::transform登录后复制登录后复制登录后复制视图包含一个运行的操作(std::this_thread::sleep_for登录后复制)。我们只访问了结果中的前10个元素,因此只有这一个10个元素的转换会被执行。如果我们要访问所有元素,那么总的执行时间就会显着增加。如何调试范围库代码?
调试范围库代码可能有些困难,因为视图是懒惰的。这意味着你不能简单地打印视图中的所有元素来查看发生的事情。相反,你需要使用调试器来逐步执行代码,并查看每个视图的中间结果。
另一种调试范围库代码的方法是使用std::ranges::登录后复制将视图转换为一个具体的容器(例如std::矢量登录后复制)。
这会强制执行所有视图操作,将结果存储在一个容器中,你可以轻松地检查该容器。
例如:#include lt;iostreamgt;#include lt;vectorgt;#include lt;rangesgt;int main() { std::vectorlt;intgt;numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto results = Numbers | std::视图::filter([](int n){ return n 2 != 0; }) | std::views::transform([](int n){ return n * n; }); // 将视图转换为支持,便于调试 std::vectorlt;intgt; Materialized_results = results | std::ranges::tolt;std::vectorgt;(); for (int result : Materialized_results) { std::cout lt;lt; result lt;lt; quot; quot;; } std::cout lt;lt; std::endl; return 0;}登录后复制范围库与其他算法的比较
范围库不一定要完全替代现有的STL它们提供了一种替代表达力、更容易组合的方式来处理序列数据,但 STL 算法在某些情况下仍然非常有用。例如,如果你需要执行一个复杂的算法,而该算法那么没有直接对应的观点,使用 STL 算法可能更合适。
范围库和 STL 算法之间的一个主要区别是,范围库迭代器对(开始和结束迭代器)来表示序列,而 STL算法通常使用单个迭代器和一个计数器。这意味着范围库可以更容易地处理无限序列或只能通过迭代器访问的序列。
总的来说,C 范围库的视图和管道操作提供了一种强大的工具,可以简化和优化序列数据的处理。通过理解视图哥的懒惰特性,自定义视图的创建,以及与其他算法的比较,你可以更有效地利用范围库来编写、且可维护的代码。
以上就是C范围库应用视图与管道操作指南的详细信息,内容更多请关注乐常识网其他相关文章!