无法将右值 std::array 转换为 std::span

Ven*_*nor 5 c++ stl std c++20

考虑以下代码。

#include <array>
#include <span>

std::array<int, 2> Foo()
{
    return {1, 2};
}

int main()
{    
    std::array a = {3, 4};
    std::span s1 = a;
    
    // std::span s2 = Foo(); // Nope
    // std::span s3 = std::move(a); // Nope
    // std::span s4 = std::array<int, 2>{5, 6}; // Nope

    // MSVC 19.29: 'initializing': cannot convert from 'std::array<int,2>' to 'std::span<int,18446744073709551615>'
    // GCC 12.0.0: conversion from 'std::array<int, 2>' to non-scalar type 'std::span<int, 18446744073709551615>' requested
    // clang 13.0.0: actually compiles!
}
Run Code Online (Sandbox Code Playgroud)

似乎只有在 clang 上它是右值时std::array才能转换为 an 。std::span

我不确定这是否是问题的根源,但这是 MSVC 的std::array相关构造函数的实现std::span

    template <class _OtherTy, size_t _Size>
        requires (_Extent == dynamic_extent || _Extent == _Size)
              && is_convertible_v<_OtherTy (*)[], element_type (*)[]>
    constexpr span(array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {}

    template <class _OtherTy, size_t _Size>
        requires (_Extent == dynamic_extent || _Extent == _Size)
              && is_convertible_v<const _OtherTy (*)[], element_type (*)[]>
    constexpr span(const array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {}
Run Code Online (Sandbox Code Playgroud)

乍一看我并没有发现有什么问题。右值应该绑定到 const 左值引用。

我的问题是:这段代码应该编译(这是前一个编译器的问题)还是不编译(这是后一个编译器的问题)?

康桓瑋*_*康桓瑋 5

TL;博士。这只是因为 libc++ 尚未实现\n P1394

\n
\n

问题是在libstd++MSVC-STL中,std::span具有以下 CTAD:

\n
template<typename _Range>\n    span(_Range &&)\n      -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;\n
Run Code Online (Sandbox Code Playgroud)\n

当我们调用时std::span{std::array{0}}, 的类型span将被推导为span<int>,并且我们将调用span<int>::span(const array<int, 1>&),但是这个构造函数有以下约束

\n
\n

约束:顺其自然Uremove_\xc2\xadpointer_\xc2\xadt<decltype(data(arr))>

\n
    \n
  • extent == dynamic_\xc2\xadextent || N == extenttrue, 和
  • \n
  • is_\xc2\xadconvertible_\xc2\xadv<U(*)[], element_\xc2\xadtype(*)[]>true
  • \n
\n
\n

arr.data()由于isconst int*element_typeis的返回类型int,值为is_convertible_v<const int(*)[], int(*)[]>false,因此不满足约束。

\n
\n

此 CTAD 在libc++中不可用,因此std::span{std::array{0}}将使用以下 CTAD:

\n
template<class _Tp, size_t _Sz>\n    span(const array<_Tp, _Sz>&) -> span<const _Tp, _Sz>;\n
Run Code Online (Sandbox Code Playgroud)\n

然后打电话span<const int, 1>::span(array<const int, 1>&),这只是……工作。

\n