std::ranges、std::views和懒加载

1、std::string::npos是C++中std::string类定义的一个静态常量,通常用于表示"未找到"或"直到字符串结束"。

常见用途:

表示查找操作,但未找到结果

cpp 复制代码
std::string str = "hello word";
size_t pos = str.find("xyz");
if(pos == std::string::npos)
{
    //查到结尾,但未找到
}

表示从某个位置开始,截取到字符串末尾

cpp 复制代码
std::string str = "hello world";
std::string sub = str.substr(6,std::string::npos);
//表示从位置6开始,截取到字符串末尾

2、惰性视图:是一种优化程序性能的编程技术。它的核心理念是:把要做的工作记录下来,但不立即执行,等到需要结果的那一刻,才进行真正的计算。

3、C++20引入的Ranges库是标准库模板STL的一次重大升级,它通过"视图"和"管道符 |"提供了一种更现代、更强大、也更安全的数据处理方式。

核心概念,Ranges库建立在几个相互关联的核心概念之上:

(1)范围:一个可以遍历的元素序列的抽象。如标准容器库vector,list,array等都是范围

(2)视图:一个轻量级的、非持有的范围,它不会复制数据,而是对底层数据进行某种操作(如筛选、转换等)并提供一个"视图"。视图的计算是惰性的,即只有在需要时才计算,这为性能优化提供了巨大空间。

(3)范围适配器:返回视图的函数或对象。它们是构建数据处理管道的基本单元,通过管道符 | 进行组合,数据从左向右流动,逻辑清晰直观。

(4)管道符:用于组合视图的操作符。R | A | B的写法让数据处理像流水线一样易于理解。

Ranges库并非仅仅是语法糖,它代表了一种全新的、更函数式的C++编程范式。

cpp 复制代码
#include <string>
#include <vector>
#include <algorithm>
#include <ranges>
#include <iostream>
int main()
{
	std::string word = "apple";
	auto hasWord = [&word](const std::string& s) {return s.find(word) != std::string::npos;};
	std::vector<std::string> words = { "apple pie", "banana split", "apple tart", "cherry cobbler" };
	auto res = words | std::views::filter(hasWord);

	for (auto s : res)
	{
		std::cout << s << std::endl;
	}

	std::vector<int> input{0,1,2,3,4,5,6,7,8,9,10};
	std::vector<int> intermediate, output;
	std::copy_if(input.begin(), input.end(), std::back_inserter(intermediate), [](int i) {return i % 3 == 0; });
	std::transform(input.begin(), input.end(), std::back_inserter(output), [](const int i) {return i * i; });
	for (auto i : intermediate)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	for (auto i : output)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;

	auto output2 = input | std::views::filter([](const int i) {return i % 3 == 0; });
	auto output3 = input | std::views::transform([](const int i) {return i * i; });
	for (auto i : output2)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	for (auto i : output3)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	auto output4 = input | std::views::filter([](const int i) {return i % 3 == 0; }) | std::views::transform([](const int i) {return i * i; });
	std::cout << "------------------" << std::endl;
	for (auto i : output4)
	{
		std::cout << i << " ";
	}
	std::cout << std::endl;
	return 0;
}

4、管道的作用

左边:数据源(容器、范围)

右边:视图适配器

效果:将数据源"喂给"视图适配器处理

5、懒加载的具体体现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <ranges>

int main() {
    std::vector<std::string> words = { "apple pie", "banana split", "apple tart" };

    int filterCalls = 0;
    auto hasApple = [&filterCalls](const std::string& s) {
        filterCalls++;
        std::cout << "Filter checking: " << s << std::endl;
        return s.find("apple") != std::string::npos;
        };

    // 创建视图 - 不会触发任何过滤检查
    auto view = words | std::views::filter(hasApple);
    std::cout << "After view creation, filter calls: " << filterCalls << std::endl;

    // 第一次遍历 - 触发过滤
    std::cout << "\nFirst iteration:\n";
    for (const auto& s : view) {
        std::cout << "  Result: " << s << std::endl;
    }
    std::cout << "Filter calls after first iteration: " << filterCalls << std::endl;

    // 第二次遍历 - 再次触发过滤
    std::cout << "\nSecond iteration:\n";
    for (const auto& s : view) {
        std::cout << "  Result: " << s << std::endl;
    }
    std::cout << "Filter calls after second iteration: " << filterCalls << std::endl;
}

与普通容器相比:

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <ranges>

int main() {
    std::vector<std::string> words = {"apple pie", "banana split", "apple tart"};
    
    // 方式1:立即求值的传统方式
    auto hasApple = [](const std::string& s) {
        return s.find("apple") != std::string::npos;
    };
    
    std::vector<std::string> eager_result;
    std::copy_if(words.begin(), words.end(), 
                 std::back_inserter(eager_result), 
                 hasApple);
    // eager_result 现在就包含了所有匹配的字符串(副本)
    
    // 方式2:惰性求值的视图方式
    auto lazy_view = words | std::views::filter(hasApple);
    // lazy_view 不包含数据,只是知道如何过滤
    
    // 主要区别:
    // 1. 内存:eager_result 占用额外内存,lazy_view 不占用
    // 2. 时间:eager_result 立即计算,lazy_view 延迟计算
    // 3. 原数据修改:lazy_view 会反映原数据的变化
}
相关推荐
CQU_JIAKE1 小时前
【a]4.25
开发语言
gCode Teacher 格码致知1 小时前
Javascript提高:一个彩色小球在画布边界内反弹并留下渐变轨迹-由Deepseek产生
开发语言·javascript
瞎折腾啥啊1 小时前
现代 CMake 目标系统
c++·cmake·cmakelists
盐焗鹌鹑蛋1 小时前
【C++】list类
c++
minji...1 小时前
Linux 网络套接字编程(六)TCP的通信是全双工的,自定义协议的定制,序列化和反序列化
linux·运维·服务器·网络·c++
Z文的博客1 小时前
【避坑实录】Qt 4.8.6 + Paho MQTT C客户端 + OpenSSL静态链接的血泪史
c语言·开发语言·qt·嵌入式linux
ximu_polaris1 小时前
设计模式(C++)-行为型模式-策略模式
c++·设计模式·策略模式
神仙别闹1 小时前
基于Python实现上下消化道病历分类
开发语言·python·分类
一行代码一行诗++1 小时前
转义字符和语句
c语言·开发语言·算法