范围库(C++20 起)

范围库(C++20 起)

C++

编译器支持

自由(freestanding)与宿主(hosted)

语言

标准库

标准库头文件

具名要求

特性测试宏 (C++20)

语言支持库

概念库 (C++20)

诊断库

内存管理库

元编程库 (C++11)

通用工具库

容器库

迭代器库

范围库 (C++20)

算法库

字符串库

文本处理库

数值库

日期和时间库

输入/输出库

文件系统库 (C++17)

并发支持库 (C++11)

执行控制库 (C++26)

技术规范

符号索引

外部库

[编辑] 范围库 (Ranges library)

范围访问

begin

cbegin

end

cend

rbegin

crbegin

rend

crend

size

ssize

data

cdata

reserve_hint(C++26)

empty

范围转换 (Range conversions)

std::from_range_tstd::from_range(C++23)(C++23)

to(C++23)

悬空迭代器处理 (Dangling iterator handling)

dangling

borrowed_iterator_t

borrowed_subrange_t

范围原语 (Range primitives)

range_size_trange_difference_trange_value_t

elements_of(C++23)

iterator_tconst_iterator_tsentinel_tconst_sentinel_t(C++23)(C++23)

range_reference_trange_const_reference_trange_rvalue_reference_trange_common_reference_t(C++23)

范围概念 (Range concepts)

range

borrowed_range

common_range

sized_range

viewable_range

view

input_range

output_range

forward_range

bidirectional_range

random_access_range

contiguous_range

approximately_sized_range(C++26)

constant_range(C++23)

视图

view_interface

subrange

范围工厂 (Range factories)

empty_viewviews::empty

single_viewviews::single

basic_istream_viewviews::istream

iota_viewviews::iota

repeat_viewviews::repeat(C++23)(C++23)

范围适配器 (Range adaptors)

views::all_tviews::all

as_rvalue_viewviews::as_rvalue(C++23)(C++23)

filter_viewviews::filter

transform_viewviews::transform

take_viewviews::take

take_while_viewviews::take_while

common_viewviews::common

views::counted

to_input_viewviews::to_input(C++26)(C++26)

ref_view

drop_viewviews::drop

drop_while_viewviews::drop_while

lazy_split_viewviews::lazy_split

split_viewviews::split

join_viewviews::join

join_with_viewviews::join_with(C++23)(C++23)

concat_viewviews::concat(C++26)(C++26)

cache_latest_viewviews::cache_latest(C++26)(C++26)

owning_view

reverse_viewviews::reverse

as_const_viewviews::as_const(C++23)(C++23)

elements_viewviews::elements

keys_viewviews::keys

values_viewviews::values

enumerate_viewviews::enumerate(C++23)(C++23)

zip_viewviews::zip(C++23)(C++23)

zip_transform_viewviews::zip_transform(C++23)(C++23)

adjacent_viewviews::adjacent(C++23)(C++23)

views::pairwise(C++23)

adjacent_transform_viewviews::adjacent_transform(C++23)(C++23)

views::pairwise_transform(C++23)

chunk_viewviews::chunk(C++23)(C++23)

slide_viewviews::slide(C++23)(C++23)

chunk_by_viewviews::chunk_by(C++23)(C++23)

stride_viewviews::stride(C++23)(C++23)

cartesian_product_viewviews::cartesian_product(C++23)(C++23)

范围生成器 (Range generators)

std::generator(C++23)

范围适配器闭包对象 (Range adaptor closure objects)

range_adaptor_closure(C++23)

范围适配器对象 (Range adaptor objects)

辅助项 (Helper items)

copyable-boxmovable-box(直到 C++23) (C++23)

simple-view

non-propagating-cache

[编辑]

范围库是算法和迭代器库的扩展和泛化,通过使其可组合且不易出错,从而使其功能更强大。

该库创建和操作范围 _视图_,它们是间接表示可迭代序列(_范围_)的轻量级对象。范围是基于以下概念的抽象:

[begin, end) – 迭代器对,例如通过从容器隐式转换创建的范围。所有接受迭代器对的算法现在都具有接受范围的重载(例如 ranges::sort)begin + [​0​, size) – 计数序列,例如 views::counted 返回的范围 [begin, _predicate_) – 条件终止序列,例如 views::take_while 返回的范围 [begin, ..) – 无界序列,例如 views::iota 返回的范围

范围库包括范围算法(它们急切地应用于范围)和范围适配器(它们懒惰地应用于视图)。适配器可以组合成管道,以便在迭代视图时执行其操作。

定义于头文件

namespace std {

namespace views = ranges::views;

}

(C++20 起)

提供了命名空间别名 std::views 作为 std::ranges::views 的简写。

定义于命名空间std::ranges

目录

1 范围访问

2 范围原语

3 悬空迭代器处理

4 其他实用工具

5 范围概念

6 范围转换

7 视图

8 范围工厂

9 范围适配器

10 范围生成器 (C++23 起)

11 辅助项

11.1 范围适配器对象

11.2 范围适配器闭包对象

11.3 定制点对象

11.4 可赋值包装器

11.5 非传播缓存

11.6 条件常量类型

11.7 类整数类型辅助模板

11.8 定制点对象辅助

11.9 范围适配器辅助

11.10 辅助概念

12 备注

13 示例

14 缺陷报告

15 另请参阅

范围访问

定义于头文件

定义于头文件

ranges::begin(C++20)

返回指向范围开头的迭代器(定制点对象)[编辑]

ranges::end(C++20)

返回指示范围末尾的哨兵(定制点对象)[编辑]

ranges::cbegin(C++20)

返回只读范围的起始迭代器(定制点对象)[编辑]

ranges::cend(C++20)

返回一个表示只读范围末尾的哨兵(定制点对象)[编辑]

ranges::rbegin(C++20)

返回指向范围的反向迭代器(定制点对象)[编辑]

ranges::rend(C++20)

返回指向范围的反向结束迭代器(定制点对象)[编辑]

ranges::crbegin(C++20)

返回只读范围的反向迭代器(定制点对象)[编辑]

ranges::crend(C++20)

返回只读范围的反向结束迭代器(定制点对象)[编辑]

ranges::reserve_hint(C++26)

返回等于范围给出的预留提示的整数(定制点对象)[编辑]

ranges::size(C++20)

返回等于范围大小的整数(定制点对象)[编辑]

ranges::ssize(C++20)

返回等于范围大小的有符号整数(定制点对象)[编辑]

ranges::empty(C++20)

检查范围是否为空(定制点对象)[编辑]

ranges::data(C++20)

获取指向连续范围开头的指针(定制点对象)[编辑]

ranges::cdata(C++20)

获取指向只读连续范围开头的指针(定制点对象)[编辑]

范围原语 (Range primitives)

定义于头文件

ranges::iterator_tranges::const_iterator_tranges::sentinel_tranges::const_sentinel_t(C++20)(C++23)(C++20)(C++23)

获取范围的迭代器和哨兵类型(别名模板)[编辑]

ranges::range_difference_tranges::range_size_tranges::range_value_t(C++20)(C++20)(C++20)

获取范围的大小、差值和值类型(别名模板)[编辑]

ranges::range_reference_tranges::range_const_reference_tranges::range_rvalue_reference_tranges::range_common_reference_t(C++20)(C++23)(C++20)(C++20)

获取范围的引用类型(别名模板)[编辑]

悬空迭代器处理 (Dangling iterator handling)

定义于头文件

ranges::dangling(C++20)

一个占位符类型,指示迭代器或 subrange 不应返回,因为它会悬空 (类) [编辑]

ranges::borrowed_iterator_tranges::borrowed_subrange_t(C++20)

获取 borrowed_range 的迭代器类型或 subrange 类型(别名模板)[编辑]

其他实用工具

定义于头文件

ranges::elements_of(C++23)

将范围标记为序列而不是单个值 (类模板) [编辑]

范围概念 (Range concepts)

定义于头文件

ranges::range(C++20)

指定类型为范围,即它提供 begin 迭代器和 end 哨兵 (概念) [编辑]

ranges::borrowed_range(C++20)

指定类型为 range,并且从其表达式获得的迭代器可以安全返回而不会有悬空的危险 (概念) [编辑]

ranges::approximately_sized_range(C++26)

指定范围可以在常数时间内估算其大小 (概念) [编辑]

ranges::sized_range(C++20)

指定范围在常数时间内知道其大小 (概念) [编辑]

ranges::view(C++20)

指定范围是视图,即它具有常数时间复制/移动/赋值 (概念) [编辑]

ranges::input_range(C++20)

指定其迭代器类型满足 input_iterator 的范围 (概念) [编辑]

ranges::output_range(C++20)

指定其迭代器类型满足 output_iterator 的范围 (概念) [编辑]

ranges::forward_range(C++20)

指定其迭代器类型满足 forward_iterator 的范围 (概念) [编辑]

ranges::bidirectional_range(C++20)

指定其迭代器类型满足 bidirectional_iterator 的范围 (概念) [编辑]

ranges::random_access_range(C++20)

指定其迭代器类型满足 random_access_iterator 的范围 (概念) [编辑]

ranges::contiguous_range(C++20)

指定其迭代器类型满足 contiguous_iterator 的范围 (概念) [编辑]

ranges::common_range(C++20)

指定范围具有相同的迭代器和哨兵类型 (概念) [编辑]

ranges::viewable_range(C++20)

指定 range 安全转换为 view 的要求 (概念) [编辑]

ranges::constant_range(C++23)

指定范围具有只读元素 (概念) [编辑]

范围转换 (Range conversions)

定义于头文件

ranges::to(C++23)

从输入范围构造新的非视图对象 (函数模板) [编辑]

视图

定义于头文件

ranges::view_interface(C++20)

用于使用奇异递归模板模式定义view的辅助类模板 (类模板) [编辑]

ranges::subrange(C++20)

将迭代器-哨兵对组合成view (类模板) [编辑]

[编辑] 范围工厂

定义于头文件

定义于命名空间std::ranges

ranges::empty_viewviews::empty(C++20)

一个不含元素的空 view(类模板) (变量模板)[编辑]

ranges::single_viewviews::single(C++20)

一个包含单个指定值的 view(类模板) (定制点对象)[编辑]

ranges::iota_viewviews::iota(C++20)

由重复递增初始值生成的序列组成的 view(类模板) (定制点对象)[编辑]

ranges::repeat_viewviews::repeat(C++23)

一个由重复生成相同值组成的view(类模板) (定制点对象)[编辑]

ranges::basic_istream_viewviews::istream(C++20)

一个view,由在相关输入流上连续应用 operator>> 获得的元素组成(类模板) (定制点对象)[编辑]

[编辑] 范围适配器

定义于头文件

定义于命名空间std::ranges

ranges::range_adaptor_closure(C++23)

用于定义范围适配器闭包对象的辅助基类模板 (类模板) [编辑]

views::all_tviews::all(C++20)

包含range所有元素的view(别名模板) (范围适配器对象)[编辑]

ranges::ref_view(C++20)

其他range元素的view (类模板) [编辑]

ranges::owning_view(C++20)

一个具有对某些range的唯一所有权的view (类模板) [编辑]

ranges::as_rvalue_viewviews::as_rvalue(C++23)

序列的 view,将每个元素转换为右值(类模板) (范围适配器对象)[编辑]

ranges::filter_viewviews::filter(C++20)

一个 view,由满足谓词的 range 的元素组成(类模板) (范围适配器对象)[编辑]

ranges::transform_viewviews::transform(C++20)

一个将转换函数应用于每个元素的序列 view(类模板) (范围适配器对象)[编辑]

ranges::take_viewviews::take(C++20)

由另一个view的前N个元素组成的view(类模板) (范围适配器对象)[编辑]

ranges::take_while_viewviews::take_while(C++20)

一个view,由另一个view的初始元素组成,直到第一个谓词返回false的元素(类模板) (范围适配器对象)[编辑]

ranges::drop_viewviews::drop(C++20)

由另一个view的元素组成的view,跳过前N个元素(类模板) (范围适配器对象)[编辑]

ranges::drop_while_viewviews::drop_while(C++20)

一个view,由另一个view的元素组成,跳过初始子序列元素,直到第一个谓词返回false的元素(类模板) (范围适配器对象)[编辑]

ranges::join_viewviews::join(C++20)

一个view,由展平ranges的view获得的序列组成(类模板) (范围适配器对象)[编辑]

ranges::join_with_viewviews::join_with(C++23)

一个 view,由扁平化范围视图获得的序列组成,元素之间带有分隔符(类模板) (范围适配器对象)[编辑]

ranges::lazy_split_viewviews::lazy_split(C++20)

一个 view,包含通过分隔符拆分另一个 view 获得的子范围(类模板) (范围适配器对象)[编辑]

ranges::split_viewviews::split(C++20)

一个 view,包含通过分隔符拆分另一个 view 获得的子范围(类模板) (范围适配器对象)[编辑]

ranges::concat_viewviews::concat(C++26)

一个 view,由连接的适配器视图组成(类模板) (定制点对象)[编辑]

views::counted(C++20)

从迭代器和计数创建子范围(定制点对象)[编辑]

ranges::common_viewviews::common(C++20)

将 view 转换为 common_range(类模板) (范围适配器对象)[编辑]

ranges::reverse_viewviews::reverse(C++20)

一个view,它以反向顺序迭代另一个双向视图的元素(类模板) (范围适配器对象)[编辑]

ranges::as_const_viewviews::as_const(C++23)

将 view 转换为 constant_range(类模板) (范围适配器对象)[编辑]

ranges::elements_viewviews::elements(C++20)

接受一个由_tuple-like_值和数字N组成的view,并生成一个由每个元组的Nth元素组成的view(类模板) (范围适配器对象)[编辑]

ranges::keys_viewviews::keys(C++20)

接受一个由类似对的值组成的view,并生成一个由每对的第一个元素组成的view(类模板) (范围适配器对象)[编辑]

ranges::values_viewviews::values(C++20)

接受一个由类似对的值组成的view,并生成一个由每对的第二个元素组成的view(类模板) (范围适配器对象)[编辑]

ranges::enumerate_viewviews::enumerate(C++23)

一个view,它将适配序列的每个元素映射到元素的索引和值的元组(类模板) (范围适配器对象)[编辑]

ranges::zip_viewviews::zip(C++23)

一个由引用到适配视图对应元素的元组组成的 view(类模板) (定制点对象)[编辑]

ranges::zip_transform_viewviews::zip_transform(C++23)

一个由转换函数应用于适配视图中对应元素的结果组成的 view(类模板) (定制点对象)[编辑]

ranges::adjacent_viewviews::adjacent(C++23)

一个 view,由适配视图相邻元素的引用元组组成(类模板) (范围适配器对象)[编辑]

ranges::adjacent_transform_viewviews::adjacent_transform(C++23)

一个 view,由对适配视图的相邻元素应用转换函数的结果组成(类模板) (范围适配器对象)[编辑]

ranges::chunk_viewviews::chunk(C++23)

一个 view 的范围,它是另一个 view 元素的 N 大小的非重叠连续块(类模板) (范围适配器对象)[编辑]

ranges::slide_viewviews::slide(C++23)

一个view,其Mth元素是一个覆盖另一个view的Mth到(M + N - 1)th元素的view(类模板) (范围适配器对象)[编辑]

ranges::chunk_by_viewviews::chunk_by(C++23)

将view分割成子范围,位于给定谓词返回false的每对相邻元素之间(类模板) (范围适配器对象)[编辑]

ranges::stride_viewviews::stride(C++23)

一个 view,由另一个 view 的元素组成,每次前进 N 个元素(类模板) (范围适配器对象)[编辑]

ranges::cartesian_product_viewviews::cartesian_product(C++23)

一个view,由适配视图的n元笛卡尔积计算出的元组组成(类模板) (定制点对象)[编辑]

ranges::cache_latest_viewviews::cache_latest(C++26)

一个view,它缓存其底层序列的最后访问元素(类模板) (范围适配器对象)[编辑]

ranges::to_input_viewviews::to_input(C++26)

将view转换为仅是input_range且非common_range的范围(类模板) (范围适配器对象)[编辑]

[编辑] 范围生成器 (C++23 起)

在头文件 中定义

定义于命名空间 std

generator(C++23)

表示同步协程生成器的view (类模板) [编辑]

[编辑] 辅助项

[编辑] 范围适配器对象

参见 RangeAdaptorObject (RAO)。

[编辑] 范围适配器闭包对象

参见 RangeAdaptorClosureObject (RACO)。

[编辑] 自定义点对象

参见 自定义点对象 (CPO)。

[编辑] 可赋值包装器

一些范围适配器使用 copyable-box(C++23 前)movable-box(C++23 起) 包装其元素或函数对象。当需要时,该包装器会为被包装对象增加可赋值性。

[编辑] 非传播缓存

一些范围适配器根据一个仅用于阐述的类模板 non-propagating-cache 指定,其行为几乎与 std::optional 相同(参见描述了解差异)。

[编辑] 条件 const 类型

template< bool Const, class T > using /*maybe-const*/ = std::conditional_t;

(仅作说明*)

别名模板 /*maybe-const*/ 是一个用于有条件地将 const 限定符应用于类型 T 的简写。

[编辑] 类整数类型辅助模板

template< /*is-integer-like*/ T > using /*make-signed-like-t*/ = /* 参见描述 */;

(1)

(仅作说明*)

template< /*is-integer-like*/ T > using /*make-unsigned-like-t*/ = /* 参见描述 */;

(2)

(仅作说明*)

template< /*is-integer-like*/ T > /*make-unsigned-like-t*/ /*to-unsigned-like*/( T t ) { return static_cast>(t);

}

(3)

(仅作说明*)

1) 对于一个 类整数类型 T如果 T 是整数类型,则 /*make-signed-like-t*/ 是 std::make_signed_t。否则,/*make-signed-like-t*/ 是一个相应未指定的、与 T 相同位宽的有符号类整数类型。

2) 对于一个类整数类型 T如果 T 是整数类型,则 /*make-unsigned-like-t*/ 是 std::make_unsigned_t。否则,/*make-signed-like-t*/ 是一个相应未指定的、与 T 相同位宽的无符号类整数类型。

3) 显式地将 t 转换为 /*make-unsigned-like-t*/

[编辑] 自定义点对象辅助函数

template< ranges::input_range R > constexpr auto& /*possibly-const-range*/(R& r) noexcept { if constexpr (ranges::input_range) return const_cast(r); else return r;

}

(1)

(仅作说明*)

template< class T > constexpr auto /*as-const-pointer*/( const T* p ) noexcept { return p;

}

(2)

(仅作说明*)

一些范围访问自定义点对象是根据这些仅用于阐述的函数模板指定的。

1) /*possibly-const-range*/ 返回 r 的 const 限定版本,如果 const R 建模 input_range;否则,不进行任何类型转换返回 r。

2) /*as-const-pointer*/ 返回指向 const 类型对象的指针。

[编辑] 范围适配器辅助函数

template< class F, class Tuple > constexpr auto /*tuple-transform*/( F&& f, Tuple&& tuple ) { return std::apply([&](Ts&&... args) { return std::tuple...> (std::invoke(f, std::forward(args))...); }, std::forward(tuple));

}

(1)

(仅作说明*)

template< class F, class Tuple > constexpr void /*tuple-for-each*/( F&& f, Tuple&& tuple ) { std::apply([&](Ts&&... args) { (static_cast(std::invoke(f, std::forward(args))), ...); }, std::forward(tuple));

}

(2)

(仅作说明*)

template< class T > constexpr T& /*as-lvalue*/( T&& t ) { return static_cast(t);

}

(3)

(仅作说明*)

一些范围适配器是根据这些仅用于阐述的函数模板指定的。

1) /*tuple-transform*/ 返回一个新的元组,该元组是通过将 f 应用于 tuple 的每个元素而构造的。

2) /*tuple-for-each*/ 将 f 应用于 tuple 的每个元素,不返回任何内容。

3) /*as-lvalue*/ 将右值 t 作为左值转发。

[编辑] 辅助概念

以下仅用于阐述的概念用于几种类型,但它们不是标准库接口的一部分。

template< class R > concept /*simple-view*/ = ranges::view && ranges::range && std::same_as, ranges::iterator_t> &&

std::same_as, ranges::sentinel_t>;

(1)

(仅作说明*)

template< class I > concept /*has-arrow*/ = ranges::input_iterator &&

(std::is_pointer_v || requires(const I i) { i.operator->(); });

(2)

(仅作说明*)

template< class T, class U > concept /*different-from*/ =

!std::same_as, std::remove_cvref_t>;

(3)

(仅作说明*)

template< class R > concept /*range-with-movable-references*/ = ranges::input_range && std::move_constructible> &&

std::move_constructible>;

(4)

(仅作说明*)

template< bool C, class... Views > concept /*all-random-access*/ = (ranges::random_access_range

> && ...);

(5)

(仅作说明*)

template< bool C, class... Views > concept /*all-bidirectional*/ = (ranges::bidirectional_range

> && ...);

(6)

(仅作说明*)

template< bool C, class... Views > concept /*all-forward*/ = (ranges::forward_range

> && ...);

(7)

(仅作说明*)

[编辑] 注意

特性测试宏

标准

特性

__cpp_lib_generator

202207L

(C++23)

std::generator – 范围的同步协程生成器

__cpp_lib_ranges

201911L

(C++20)

Ranges 库和 受限算法

202106L

(C++23)(DR20)

不可默认初始化的视图

202110L

(C++23)(DR20)

带有所有权的视图

202202L

(C++23)

ranges::range_adaptor_closure

202207L

(C++23)

放宽范围适配器以允许仅可移动类型

202211L

(C++23)

移除 ranges::begin 等中的“毒丸”(P2602) 重载

202302L

(C++23)

放宽范围以允许某些投影

202406L

(C++26)(DR20)

移除间接可调用概念中的 common reference 要求

__cpp_lib_ranges_as_const

202207L

(C++23)

std::const_iterator, ranges::as_const_view

__cpp_lib_ranges_as_rvalue

202207L

(C++23)

ranges::as_rvalue_view

__cpp_lib_ranges_cache_latest

202411L

(C++26)

ranges::cache_latest_view

__cpp_lib_ranges_cartesian_product

202207L

(C++23)

ranges::cartesian_product_view

__cpp_lib_ranges_chunk

202202L

(C++23)

ranges::chunk_view

__cpp_lib_ranges_chunk_by

202202L

(C++23)

ranges::chunk_by_view

__cpp_lib_ranges_concat

202403L

(C++26)

ranges::concat_view

__cpp_lib_ranges_enumerate

202302L

(C++23)

ranges::enumerate_view

__cpp_lib_ranges_join_with

202202L

(C++23)

ranges::join_with_view

__cpp_lib_ranges_repeat

202207L

(C++23)

ranges::repeat_view

__cpp_lib_ranges_reserve_hint

202502L

(C++26)

ranges::reserve_hint 和 ranges::approximately_sized_range

__cpp_lib_ranges_slide

202202L

(C++23)

ranges::slide_view

__cpp_lib_ranges_stride

202207L

(C++23)

ranges::stride_view

__cpp_lib_ranges_to_container

202202L

(C++23)

ranges::to

__cpp_lib_ranges_to_input

202502L

(C++26)

ranges::to_input_view

__cpp_lib_ranges_zip

202110L

(C++23)

ranges::zip_view,ranges::zip_transform_view,ranges::adjacent_view,ranges::adjacent_transform_view

[编辑] 示例

运行此代码

#include

#include

int main()

{

auto const ints = {0, 1, 2, 3, 4, 5};

auto even = [](int i) { return 0 == i % 2; };

auto square = [](int i) { return i * i; };

// the "pipe" syntax of composing the views:

for (int i : ints | std::views::filter(even) | std::views::transform(square))

std::cout << i << ' ';

std::cout << '\n';

// a traditional "functional" composing syntax:

for (int i : std::views::transform(std::views::filter(ints, even), square))

std::cout << i << ' ';

}

输出

0 4 16

0 4 16

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告

应用于

发布时的行为

正确的行为

LWG 3509(P2281R1)

C++20

不清楚范围适配器对象如何绑定尾随参数

它们按值绑定按值

LWG 3948

C++23

possibly-const-range 和 as-const-pointer未声明为 noexcept

声明为 noexcept

LWG 4027

C++23

对于已建模 constant_range 的范围,possibly-const-range 不会添加 const-限定符对于已建模 constant_range 的范围,possibly-const-range 不会添加 const-限定符

为这些范围添加 const-限定符为这些范围

LWG 4112

C++20

has-arrow 不要求 i 为 const-限定符

要求

[编辑] 参见

迭代器库

受约束算法

相关文章

地下城下载需要多少个g 地下城下载安装要多大内存 365约彩app怎么没有了

地下城下载需要多少个g 地下城下载安装要多大内存

📅 07-21 👁️ 6836
如何给分销商品设置限购? 365体育足球中文版

如何给分销商品设置限购?

📅 08-20 👁️ 2025