C++ 为什么span';s数组和std::数组构造函数与其容器构造函数不同

C++ 为什么span';s数组和std::数组构造函数与其容器构造函数不同,c++,c++20,std-span,C++,C++20,Std Span,我一直在使用Godbolt上的clang trunk和libc++来研究std::span的最新规范,发现一些构造函数令人困惑 特别是,我发现来自普通旧数组和std::array的构造函数与其他容器不同 例如,要编译的代码如下: std::vector<int*> v = {nullptr, nullptr}; std::span<const int* const> s{v}; std::vector v={nullptr,nullptr}; std::span s{v

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

特别是,我发现来自普通旧数组和
std::array
的构造函数与其他容器不同

例如,要编译的代码如下:

std::vector<int*> v = {nullptr, nullptr};
std::span<const int* const> s{v};
std::vector v={nullptr,nullptr};
std::span s{v};
但是,这并不是:

std::array<int*, 2> a = {nullptr, nullptr}; 
std::span<const int* const> s{a};
std::数组a={nullptr,nullptr};
std::span s{a};

这似乎与事实相符,我只是在努力理解为什么会出现这种情况。有人能解释一下吗?

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

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;
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;
模板constepr span(数组和arr)无异常;
模板constexpr span(const数组和arr)无异常;
但可能应指定为:

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;
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;
模板
需要std::可转换为
constexpr span(数组和arr)无异常;
模板
需要std::可转换为
constexpr span(const数组和arr)无异常;
这将使您的示例能够编译,因为这样做是安全的。我提交了一个LWG问题。这是现在


措辞中已指定了此约束:

模板constepr span(元素类型(&arr)[N])无例外;
模板constepr span(数组和arr)无异常;
模板constexpr span(const数组和arr)无异常;
限制条件:

  • extent==dynamic|extent | N==extent
    true
    ,并且
  • 删除指针(*)[]
    可转换为
    元素类型(*)[]

所以我们已经有了正确的约束。只是在这些情况下,
data(arr)
实际上并不依赖于任何一种情况,因此基本上满足了约束。我们只需要制作这些模板

令人惊讶的是,文档中确实指出:“如果extent==std::dynamic_extent | | N==extent为true,并且std::remove_pointer_t(*)[]可转换为元素_type(*)[]”@Timo Oh,奇怪。是的,我们确实有这样的措辞。。。除了数组的底层类型不是模板之外……这正是我发现的令人困惑的地方,特别是对于普通的旧数组,元素类型和值类型的具体选择。为什么他们会不同?