“viewable_range”概念的意义是什么?

5

[range.refinements]

可视范围概念指定了一种可以安全转换为视图的范围类型的要求。

强制实现规定,如果一个range进一步满足viewable_range,则:

  1. 它只是一个视图,例如std::string_view,或者
  2. 它是左值引用(即使其去除引用的类型不是视图),例如std::vector<int>&,或者
  3. 它是可移动的对象类型(即不是引用类型),例如std::vector<int>

我的问题是:

  1. 这个概念捕获了什么样的想法?具体而言,它的实例如何“可以安全转换为视图”,我为什么需要这样的转换?这里的“安全”是什么意思?
  2. 您是否总是使用viewable_range来限制通用引用?(即唯一机会T被推导为左值引用类型。)这是标准范围适配器(闭包)对象的情况。
  3. 自C++23起,范围适配器(闭包)对象已修改为将range作为第一个参数。自那时以来,是否还有其他用途可以使用viewable_range概念?
  4. 对于应用程序开发,何时使用viewable_range而不是viewrange

大多数视图实际上并不拥有元素,它们只包含指向底层范围的指针。viewable_range 允许我们将范围转换为 view,而不必担心悬空问题。 - 康桓瑋
1个回答

5
这个概念捕捉了什么样的思想?具体来说,它的实例“如何安全地转换为视图”,我为什么要进行这样的转换?在这里,“安全”是什么意思?
任何范围都可以通过简单地执行以下操作转换为视图:
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而不是viewrange
这实际上是与(2)相同的问题。如果你想要将任何范围转换为视图以进行存储,那么你就使用viewable_range,因此当你编写一个范围适配器时使用。

嗨,Barry。如果底层的非视图范围首先被销毁,那么所有覆盖它的view都会悬空 - 即使它们满足viewable_range?那么,如何使satisfying viewable_rangeT更安全地使用ref_view<T>?或者换句话说 - 不满足viewable_range如何增加悬挂的担忧? - SedriX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接