这个概念捕捉了什么样的思想?具体来说,它的实例“如何安全地转换为视图”,我为什么要进行这样的转换?在这里,“安全”是什么意思?
任何范围都可以通过简单地执行以下操作转换为视图:
template <input_range R>
auto into_view(R&& r) {
return ref_view(r);
}
但这并不是一个好主意。如果我们有一个rvalue范围(无论它是否是视图),现在我们正在引用它,因此如果我们持有结果视图的时间太长,它可能会悬空。
一般来说,我们不希望持有对视图的引用 - 视图的目的是范围适配器通过值而不是引用来持有它们。但同样一般地,我们也不想通过值来持有非视图范围,因为那些复制起来很昂贵。
viewable_range
的作用是将范围的集合限制为那些我们可以转换为视图而不必担心悬挂的范围:
view
应该总是按值传递 - 因此,如果它可以被复制,那么lvalue view
才是一个viewable_range
。rvalue view
始终是一个viewable_range
(因为view
必须是可移动的)。
- 一个非
view
的lvalue范围总是一个viewable_range
,因为在这种情况下我们采用ref_view
。当然,这可能会导致悬挂,但我们采用的是lvalue,所以这是更安全的情况。
- 最初被拒绝的非
view
rvalue范围(因为我们唯一的选择是ref_view
,而我们不想在这种情况下引用),但将开始被捕获为owning_view
(自P2415起)。
基本上,唯一不可视范围的是 lvalue 非可复制视图,因为避免对视图取引用。
“你是否总是使用 viewable_range 作为通用转发引用的限制条件?(即 T 被推导为左值引用类型的唯一机会。)这是标准范围适配器(闭包)对象的情况。”
不是的。只有当您想要使用转发引用将其转换为视图并存储结果视图时,才需要使用该限制条件。范围适配器会这样做,但算法不需要这样做 - 因此它们不应使用该约束条件(标准库算法中没有一个使用该条件)。
“自 C++23 起,范围适配器(闭包)对象已修改为以范围作为第一个参数。那么从那时起,是否还有其他用途可以使用 viewable_range 概念?”
术语 “范围适配器闭包对象” 已放宽,因为现在我们可以有用户定义的范围适配器闭包对象
P2387,我们无法真正强制执行它们实际执行的操作。
但是标准库范围适配器闭包对象仍然需要
viewable_range
(通过
all_t
)。
对于应用程序开发,何时使用
viewable_range
而不是
view
或
range
?
这实际上是与(2)相同的问题。如果你想要将任何范围转换为视图以进行存储,那么你就使用
viewable_range
,因此当你编写一个范围适配器时使用。
viewable_range
允许我们将范围转换为view
,而不必担心悬空问题。 - 康桓瑋