一、背景介绍
C++23 引入了 std::ranges::range_adaptor_closure
,这是一个辅助类模板,用于定义用户自定义的范围适配器闭包对象。这一特性主要来源于 P2387R3 提案,旨在支持用户定义的范围适配器与标准库视图适配器在管道表达式中的互操作。
二、ranges::range_adaptor_closure
的定义与要求
std::ranges::range_adaptor_closure
是一个类模板,用于确保用户定义的类型 T
是一个范围适配器闭包对象。具体要求如下:
- 单参数函数对象:
T
必须是一个单参数函数对象,接受一个范围作为参数。 - 单一基类:
T
必须恰好有一个公共基类std::ranges::range_adaptor_closure<T>
,且不能有其他类型的std::ranges::range_adaptor_closure<U>
作为基类。 - 非范围类型:
T
本身不能是一个范围。
三、使用示例
以下是一个使用 std::ranges::range_adaptor_closure
的示例,展示如何定义一个简单的范围适配器闭包对象:
#include <ranges>
#include <string_view>
#include <iostream>
// 定义一个范围适配器闭包对象
struct Slice : std::ranges::range_adaptor_closure<Slice>
{
std::size_t start = 0;
std::size_t end = std::string_view::npos;
constexpr std::string_view operator()(std::string_view sv) const
{
return sv.substr(start, end - start);
}
};
int main()
{
constexpr std::string_view str = "01234567";
// 使用 Slice 作为普通函数对象
constexpr Slice slicer{.start = 1, .end = 6};
constexpr auto sv1 = slicer(str);
std::cout << "sv1: " << sv1 << std::endl;
// 使用 Slice 作为范围适配器闭包对象
constexpr auto sv2 = str | slicer;
std::cout << "sv2: " << sv2 << std::endl;
// 范围适配器闭包可以组合
constexpr auto slice_and_drop = slicer | std::views::drop(2);
std::cout << "slice_and_drop: " << str | slice_and_drop << std::endl;
}
四、编译器支持情况
截至 2023 年 5 月,主流编译器对 std::ranges::range_adaptor_closure
的支持情况如下:
编译器 | 支持情况 |
---|---|
GCC libstdc++ | 13(部分支持),14 完全支持 |
Clang libc++ | 19 完全支持 |
MSVC STL | 19.34 完全支持 |
Apple Clang | 未明确支持 |
五、总结
C++23 的 std::ranges::range_adaptor_closure
提供了一种强大的机制,允许开发者定义自己的范围适配器闭包对象,并与标准库中的视图适配器无缝互操作。这一特性极大地增强了 C++ 范围库的灵活性和表达能力,使得范围操作更加简洁和高效。