为什么 string_view 而不是广义的 container_view<T>?

Why string_view instead of generalized container_view<T>?

我发现来自新 C++17 标准的 string_view 有点多余。

我们已经为 passing data to callee 收集了一组非常详细的简单机制,没有太多开销,现在还有一个也只针对一种容器类型。

我不明白为什么只为字符串提供这种机制,而不为其他容器提供更通用的类型。一个明智的答案是我们已经有了这些解决方案。例如,在 C++17 and beyond 中,string_view 被解释为 observer_ptr<T> (or T*) for string

请说明反对更通用的 container_view 的论点,与 C++17 引入的 string_view 形成对比。

string_view 提供的不仅仅是一个简单的字符串指针。 您需要将其视为一个简单的非拥有指针:如果仅此而已,string_view 将不允许您对字符串的 "slice" 部分进行操作,并对其应用操作(虽然仍然是一个视图;因此不会产生复制成本):

char *s = "welcome to Whosebug";
auto s = std::string_view{s + 8, 2}; // a view on "to"
// you can then apply many operations on this view, that wouldn't make sense more on your general non_owning<T>:
s.remove_prefix(std::min(s.find_first_not_of(" "), s.size()));
// it also "inherits" (copies the API) a lot directly from std::basic_string
auto view2 = s.substr(3, 4); // a generic non-owning ptr would copy here, instead of giving you a new view

广义的 container_view 更恰当地称为 范围 。我们有一个 TS 途中完全致力于范围概念。

现在,我们将 string_view 作为一个单独的类型,因为它有一个专门的、特定于字符串的接口来匹配 basic_string 的特定于字符串的接口。或者至少,匹配 const/non-allocating 接口。

请注意,container_view 或您所称的任何名称都无法删除它与生成它的容器的连接。或者至少,不是没有为每个 access/operation.

支付类型擦除开销

相比之下,string_view 基于 const char* 和整数。 class 不关心字符串来自哪里;它提供了一个连续的字符数组的视图,无论它是谁拥有的。它可以这样做是因为它知道源是一个连续的数组,因此使用指针作为其迭代器的核心。

您不能对任意容器执行此操作。您的 container_view<vector> 将具有与 container_view<list> 或其他任何不同的迭代器。它 必须 。这意味着如果你将 container_view 作为函数参数,你必须选择一个特定的容器来使用(强制用户提供确切的容器类型),使你的函数成为模板,或者使用类型擦除的迭代器范围(因此变慢)。

对于 GSL 类型 spanmdspan,还有 post-C++17 提案。前者表示 连续 数组的可修改 "view"。后者表示您视为多维的连续数组的可修改 "view"。