【问题标题】:Why is std::span a pointer + size and not two iterators为什么 std::span 是指针+大小而不是两个迭代器
【发布时间】:2019-11-10 16:18:21
【问题描述】:

似乎 C++20 中的std::span 的定义类似于

template<class T>
class span
     {
     T* begin;
     size_t count;
     };

不是

template<class Iter>
class span
     {
     Iter begin;
     Iter end;
     };

哪个更通用(适用于 std::list、std::map 等)?

【问题讨论】:

    标签: c++ c++20 std-span


    【解决方案1】:

    std::span&lt;T&gt; 的全部意义在于查看连续数据。 pair&lt;T*, size_&gt;(或类似的东西)是表示该视图的正确方法。你不能有一个std::spanstd::liststd::map 的视图,所以想出一种表示它的方法是没有意义的。关键是要成为一个通用的词汇类型,只接受连续的数据。

    span 被有效地类型擦除也很重要。 span&lt;int&gt; 可以引用 int[20]vector&lt;int&gt;int[] 动态分配的某处或 llvm::SmallVector&lt;int&gt; 或...它来自哪里并不重要,您只需拥有一种类型是:“查看一些连续的ints”。

    确实,pair&lt;Iter, Iter&gt;(或更一般地说,pair&lt;Iter, Sentinel&gt;)是一种更通用的表示形式,适用于更多容器。 C++20 中也有这样的东西,叫做std::ranges::subrange&lt;I, S&gt;。但请注意,我们没有类型擦除方面...subrangemap&lt;K, V&gt; 的类型不同@ 或vector&lt;pair&lt;K const, V&gt;&gt;multimap&lt;K, V&gt;

    【讨论】:

    • 但是你可以在任何地方使用子范围,否则你会使用跨度。不同类型的原因是,如果您对简单的情况使用单独的类,您可以提供更优化的实现吗?
    • @user877329 这不是“最佳”的问题...subrange&lt;T*&gt; 在表示方面基本上等同于span&lt;T&gt;。但是它们有不同的可用性。 vector&lt;T&gt; 绝对可以转换为span&lt;T&gt;,但不一定可以转换为subrange&lt;T*&gt;。模板参数也有不同的含义,T vs T*span 只是针对更具体的用例的更具体的东西。
    • @user877329:“但是你可以在任何地方使用子范围,否则你会使用跨度。”不,你不能。您可以将span 的数据传递给C API;你不能用任意的迭代器子范围来做到这一点。
    • @Barry subrange&lt;T*&gt; range{vec.data(), vec.data() + size()};,如果子范围 ctor 接受两个迭代器。
    • @NicolBolas 如果Iter 是一个指针,我应该可以这样做。此外,即使我可以将它传递给 C API,也必须存在这样的 API,并且大多数 C API:s 使用指针和大小,而不是 span 结构,因此除非您重写 POSIX,否则 C 兼容性并不是什么大问题或 Windows API,以及一堆其他 C 库,而你没有。当然,调用 foo(T*, size_t) 在汇编中看起来与 foo(std::span&lt;T&gt;) 完全相同,但强制使用不同的函数签名肯定是 UB。
    猜你喜欢
    • 2017-05-13
    • 2015-12-18
    • 2021-01-19
    • 2011-09-17
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    相关资源
    最近更新 更多