【问题标题】:gsl::array_view<const gsl::cstring_view<>> from std::vector<std::string>gsl::array_view<const gsl::cstring_view<>> from std::vector<std::string>
【发布时间】:2015-10-28 14:13:54
【问题描述】:

假设我在一个类中有一个成员变量std::vector&lt;std::string&gt;,我想使用gsl::array_viewgsl::cstring_view 的组合将它作为不可变视图从成员函数返回。不幸的是,以下内容无法编译:

class C {
public:
    gsl::array_view<const gsl::cstring_view<>> getVectorOfStrings() const 
    { 
         return _vectorOfStrings; 
    }

private:
    std::vector<std::string> _vectorOfStrings;
};

原因是没有cstring_view 的容器可以用来创建array_view。所以我的问题是:有没有办法在不显式添加std::vector&lt;gsl::cstring_view&lt;&gt;&gt; 类型的成员的情况下使用这样的构造,这显然是不可取的?

编辑

在我看来,这种“转变”的观点可能更普遍。考虑拥有一个拥有指针的vector,例如std::vector&lt;std::shared_ptr&lt;T&gt;&gt;,我想将其作为原始指针的array_view 暴露给类的用户:gsl::array_view&lt;const T*&gt;,而不暴露我的实现定义的存储方法。想法?

【问题讨论】:

  • 有了cstring_views 的这个理论上的array_view,谁将拥有cstring_views 的集合,cstring_views 的array_view 的存在需要它的存在?
  • @jaggedSpire 嗯,这正是我在问题的最后一段中所说的。但也许有某种惰性求值 array_view 的方法,可以根据要求将任何 string_view 兼容数组值转换为 string_view。我可能会写这样的东西,但我认为也许有更好的方法。因此这个问题:)
  • 啊。如果您想引用可以轻量级转换为cstring_views 的非拥有集合,请问为什么要避免array_viewstd::strings
  • @jaggedSpire 是的,这实际上就是我现在在代码中的内容。但是,如果其他子类将其字符串存储为std::vector&lt;const char*&gt; 怎么办?这是一种“学术”兴趣,如果其他人认为它有用(谁知道?),可能会对 gsl 做出一些贡献。
  • 我(以我有限的经验:P)能想到的那些方法的唯一替代方法是构建一个cstring_views 的向量并将其传递出要转换为的函数客户代码认为合适。如果客户端在一个表达式中需要它,它可以作为临时返回,客户端可以构造一个array_view 内联。否则,他们可以只保留向量并根据需要从中构造array_views。当然,您需要在每次需要时都构造它,因此只有在需要将 array_view&lt;cstring_view&gt; 传递给函数时才有意义

标签: c++ c++14 array-view string-view cpp-core-guidelines


【解决方案1】:

根据定义,视图通常只提供对现有对象的引用。因此,如果不首先创建一个匹配的容器,例如,就无法创建一个普通的array_view&lt;const cstring_view&lt;&gt;&gt;vector&lt;const cstring_view&lt;&gt;&gt;

但是,您可以做的是为gsl::array_view&lt;const cstring_view&lt;&gt;&gt; 创建自己的特化,按需创建cstring_view&lt;&gt;(当调用索引运算符和取消引用迭代器时)。虽然与幼稚的方法相比,这可以为您节省动态内存分配并减少内存占用,但在大多数情况下增加复杂性并不值得。

如果您想遵循编辑中描述的通用方法,您可能想查看boost::transform_iterator - 直接使用或作为您自己的通用transform_array_view 类的灵感(我是当然,这将是 gsl 或 boost 的一个受欢迎的补充)。

【讨论】:

  • 好吧,经过更多研究,在我看来,array_view(或现在称为span)在设计上不适合此目的。 span 期望某种数据类型的连续存储,所以基本上可以通过调用data() 来处理它。最后,我使用了any_rangetransformed 范围适配器。我还是觉得这可能是一个有趣的讨论,所以我会在 GSL 的 github 上提出一个讨论。