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 会反映原数据的变化
}

