为什么span的array和std :: array构造函数与其容器构造函数不同

Joh*_*n M 14 c++ c++20 std-span

我一直在研究std::span在Godbolt上使用clang干线和libc ++ 的最新规范,并发现一些令人困惑的构造函数。

特别是,我从一个普通的旧数组中发现了构造函数,并且a std::array与其他容器不同。

例如,以下代码似乎可以编译:

std::vector<int*> v = {nullptr, nullptr};
std::span<const int* const> s{v};
Run Code Online (Sandbox Code Playgroud)

但是,这不是:

std::array<int*, 2> a = {nullptr, nullptr}; 
std::span<const int* const> s{a};
Run Code Online (Sandbox Code Playgroud)

这似乎与cppreference.com上描述构造函数的方式保持一致,我只是在努力理解为什么是这种情况。有人可以照亮吗?

Bar*_*rry 8

这似乎是一个疏忽。数组构造函数当前指定为:

template<size_t N> constexpr span(array<value_type, N>& arr) noexcept;
template<size_t N> constexpr span(const array<value_type, N>& arr) noexcept;
Run Code Online (Sandbox Code Playgroud)

但可能应指定为:

template<class T, size_t N>
    requires std::convertible_to<T(*)[], ElementType(*)[]>
  constexpr span(array<T, N>& arr) noexcept;
template<class T, size_t N>
    requires std::convertible_to<const T(*)[], ElementType(*)[]>
  constexpr span(const array<T, N>& arr) noexcept;
Run Code Online (Sandbox Code Playgroud)

这样可以安全地进行编译。我提交了LWG问题。现在是LWG 3255


措词已经[span.cons] / 11中指定了此约束:

template<size_t N> constexpr span(element_type (&arr)[N]) noexcept;
template<size_t N> constexpr span(array<value_type, N>& arr) noexcept;
template<size_t N> constexpr span(const array<value_type, N>& arr) noexcept;
Run Code Online (Sandbox Code Playgroud)

限制条件

  • extent == dynamic_­extent || N == extenttrue
  • remove_­pointer_­t<decltype(data(arr))>(*)[]可转换为ElementType(*)[]

因此,我们已经有了正确的约束。只是data(arr)在所有这些情况下实际上都不依赖,因此可以轻松满足约束条件。我们只需要制作这些模板。

  • 令人惊讶的是,文档确实声明了它:_“这些扩展仅在extent == std :: dynamic_extent || N == range为true **并且std :: remove_pointer_t &lt;decltype(std :: data(arr))时才参与过载解析。 &gt;(*)[]可转换为element_type(*)[] **“ _ (2认同)