std::ranges::views::as_const 和 std::ranges::as_const_view
std::ranges::views::as_const
和 std::ranges::as_const_view
是 C++23 引入的视图适配器,用于生成一个不可变的视图,确保通过该视图访问元素时,元素被视为常量。以下是详细说明和示例:
基本概念
-
功能:
-
将输入范围的元素强制视为
const
,防止意外修改。 -
生成一个惰性视图,不复制数据,仅在访问时应用常量性。
-
-
输入要求:
-
输入范围可以是任何类型的范围(如
vector
、list
或自定义范围)。 -
不修改原始数据,仅修改访问权限。
-
函数原型
在标头 | ||
template< ranges::view V > requires ranges::input_range<V> | (1) | (C++23 起) |
namespace views { inline constexpr /* 未指明 */ as_const = /* 未指明 */; } | (2) | (C++23 起) |
调用签名 | ||
template< ranges::viewable_range R > requires /* 见下文 */ constexpr ranges::view auto as_const( R&& r ); | (C++23 起) |
参数与返回值
-
参数:
-
输入范围
r
(需满足viewable_range
)。
-
-
返回值:
as_const_view
对象,表示只读视图。 -
行为:
-
若输入范围的元素类型已为
const
,视图行为不变。 -
若元素可修改,通过视图访问时变为
const
。
-
数据成员
成员 | 说明 |
V base_ (私有) | 底层视图 (仅用于阐述的成员对象*) |
成员函数
(构造函数) | 构造一个 as_const_view (公开成员函数) |
base | 返回底层视图 V (公开成员函数) |
begin | 返回 as_const_view 的首迭代器(公开成员函数) |
end | 返回 as_const_view 的尾迭代器(公开成员函数) |
size | 如果其有界则返回视图的大小 (公开成员函数) |
reserve_hint (C++26) | 返回底层 approximately_sized_range 的估计大小 (公开成员函数) |
继承自 std::ranges::view_interface | |
empty | 返回视图是否为空,仅当视图满足 forward_range 时提供 ( std::ranges::view_interface<D> 的公开成员函数) |
cbegin (C++23) | 返回指向范围起始的常量迭代器 ( std::ranges::view_interface<D> 的公开成员函数) |
cend (C++23) | 返回对应于范围常量迭代器的哨位 ( std::ranges::view_interface<D> 的公开成员函数) |
operator bool | 返回派生视图是否为非空,仅当 ranges::empty 可应用于它时提供 ( std::ranges::view_interface<D> 的公开成员函数) |
data | 返回派生视图的数据的地址,仅当视图的迭代器类型满足 contiguous_iterator 时提供 ( std::ranges::view_interface<D> 的公开成员函数) |
front | 返回派生视图中的首元素,仅当视图满足 forward_range 时提供 ( std::ranges::view_interface<D> 的公开成员函数) |
back | 返回派生视图中的末元素,仅当视图满足 bidirectional_range 与 common_range 时提供 ( std::ranges::view_interface<D> 的公开成员函数) |
operator[] | 返回派生视图中的第 n 个元素,仅当视图满足 random_access_range 时提供( std::ranges::view_interface<D> 的公开成员函数) |
示例代码
基础用法:禁止修改元素
#include <ranges>
#include <vector>
#include <iostream>int main()
{std::vector<int> vec = {1, 2, 3, 4, 5};auto const_view = vec | std::views::as_const;for (const auto& elem : const_view) {// elem 类型为 const int&,以下代码将编译失败// elem = 10; // Error: 无法修改常量引用std::cout << elem << " ";}// 输出:1 2 3 4 5
}
结合算法确保只读操作
#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>void process_data(std::ranges::input_range auto&& r)
{// 确保 r 的元素为只读for (const auto& elem : r | std::views::as_const) {// elem 不可修改std::cout << elem << " ";}
}int main()
{std::vector<int> data = {10, 20, 30};process_data(data); // 安全传递只读视图
}
处理嵌套数据结构
#include <ranges>
#include <vector>
#include <list>int main()
{std::vector<std::list<int>> nested = {{1, 2}, {3, 4}, {5, 6}};auto const_nested = nested | std::views::as_const;for (const auto& inner_list : const_nested) {// inner_list 是 const std::list<int>&for (const auto& num : inner_list) {// num 是 const int&std::cout << num << " ";}}// 输出:1 2 3 4 5 6
}
高级用法
链式视图操作
#include <ranges>
#include <vector>
#include <algorithm>
#include <iostream>int main()
{std::vector<int> vec = {5, 3, 4, 1, 2};auto view = vec | std::views::filter([](int x) { return x % 2 == 0; }) // 筛选偶数| std::views::as_const; // 结果转为只读// 尝试修改会编译失败// *view.begin() = 10; // Error: 无法修改常量引用for (int x : view) {std::cout << x << " "; // 输出:4 2}
}
处理代理引用(如 vector<bool>
)
#include <ranges>
#include <vector>
#include <iostream>int main()
{std::vector<bool> flags = {true, false, true};auto const_flags = flags | std::views::as_const;for (const auto& flag : const_flags) {// flag 类型为 const bool&(代理引用)std::cout << std::boolalpha << flag << " ";}// 输出:true false true
}
注意事项
-
常量性传递:
-
若原始元素已为
const
,视图不会改变其行为。 -
对非
const
元素,视图强制其视为const
。
-
-
性能与开销:
-
惰性求值,无额外内存开销。
-
仅修改类型系统,运行时无性能损失。
-
-
适用场景:
-
传递范围给函数时强制只读。
-
在多线程或需要数据不变性时增强安全性。
-
-
与
const_cast
的区别:-
as_const_view
通过类型系统安全地添加常量性,而非强制转换。
-
总结
-
std::ranges::views::as_const
提供了一种类型安全的方式,确保通过视图访问的元素不可修改。 -
适用于需要强制数据只读性的场景,增强代码安全性和可维护性。
-
与标准算法和其他视图适配器无缝结合,支持复杂的链式操作。