考虑以下代码。
#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 左值引用。
我的问题是:这段代码应该编译(这是前一个编译器的问题)还是不编译(这是后一个编译器的问题)?
TL;博士。这只是因为 libc++ 尚未实现\n P1394。
\n问题是在libstd++和MSVC-STL中,std::span具有以下 CTAD:
template<typename _Range>\n span(_Range &&)\n -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;\nRun Code Online (Sandbox Code Playgroud)\n当我们调用时std::span{std::array{0}}, 的类型span将被推导为span<int>,并且我们将调用span<int>::span(const array<int, 1>&),但是这个构造函数有以下约束:
\n\n约束:顺其自然
\nU吧remove_\xc2\xadpointer_\xc2\xadt<decltype(data(arr))>。\n
\n- \n
extent == dynamic_\xc2\xadextent || N == extent是true, 和- \n
is_\xc2\xadconvertible_\xc2\xadv<U(*)[], element_\xc2\xadtype(*)[]>是true。
arr.data()由于isconst int*和element_typeis的返回类型int,值为is_convertible_v<const int(*)[], int(*)[]>false,因此不满足约束。
此 CTAD 在libc++中不可用,因此std::span{std::array{0}}将使用以下 CTAD:
template<class _Tp, size_t _Sz>\n span(const array<_Tp, _Sz>&) -> span<const _Tp, _Sz>;\nRun Code Online (Sandbox Code Playgroud)\n然后打电话span<const int, 1>::span(array<const int, 1>&),这只是……工作。