【问题标题】:why can't I construct an std::span from iterators?为什么我不能从迭代器构造一个 std::span ?
【发布时间】:2021-01-19 00:54:55
【问题描述】:

考虑一个大型内存容器。在这个简单的例子中,std::vector<int>:

std::vector v = { 0, 1, 2, 3, 4, 5 };

std::span 允许我在内存上创建一个轻量级视图。现在我想简单地打印跨度:

template<typename T>
void print(std::span<T> span) {
    std::cout << '[';
    if (span.size())
        std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));

    std::cout << span.back() << "]\n";
}

int main() {
    std::vector v = { 0, 1, 2, 3, 4, 5 };

    print(std::span{ v });
}

输出:

[0, 1, 2, 3, 4, 5]

现在我想制作子集(这是 std::span 实际上作为视图变得有用的地方)。我可以使用迭代器来指定我的范围并从std::span 调用this constructor(3)

template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );

但这不起作用:

print(std::span{ v.begin() + 2, v.end() }); //error E0289

C++ 没有构造函数实例匹配参数列表参数类型是: (std::_Vector_iterator<:_vector_val std::_simple_types std::_vec_iter_types size_t ptrdiff_t int const>>>>, std::_Vector_iterator<:_vector_val std::_simple_types std::_vec_iter_types size_t ptrdiff_t int const>>>>)


有可能使用带有指针和大小的构造函数(2):

print(std::span{ v.data() + 1, 3 }); //-> prints [1, 2, 3]

但这违背了迭代器的目的。

如何使用迭代器构造std::span?我错过了什么吗?


完整代码:

#include <iostream>
#include <vector>
#include <span>
#include <algorithm>

template<typename T>
void print(std::span<T> span) {
    std::cout << '[';
    if (span.size())
        std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));

    std::cout << span.back() << "]\n";
}

int main() {
    std::vector v = { 0, 1, 2, 3, 4, 5 };

    print(std::span{ v.begin() + 2, v.end() });
}

在 MSVC 实现构造函数之前,我将使用这个 make_span 函数:

template<typename It>
constexpr auto make_span(It begin, It end) {
    return std::span<std::remove_pointer_t<It::pointer>>(&(*begin), std::distance(begin, end));
}

使用 Visual Studio Community 2019 版本 16.7.5。配置:x64,发布。 C++ 语言标准 = /std:c++latest

【问题讨论】:

  • 我会责怪一个过时的标准库(毕竟这都是非常新的),因为 GCC 很好。 LLVM 看起来可能还需要一分钟。 Godbolt

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


【解决方案1】:

您可以使用迭代器构造一个span,它具有such a constructor(由P1394 添加,您可以在[views.span] 中看到):

template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );

只是MSVC的标准库没有实现而已。正如预期的那样,程序在 gcc 上编译得很好。

【讨论】:

  • 现在更有意义了,我只是很困惑他们为什么要部分实现构造函数。我猜我现在必须使用自定义的make_span(first, last)
猜你喜欢
  • 1970-01-01
  • 2021-10-27
  • 1970-01-01
  • 2019-11-10
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多