diff --git a/libcxx/include/span b/libcxx/include/span --- a/libcxx/include/span +++ b/libcxx/include/span @@ -212,8 +212,16 @@ { (void)__l; _LIBCPP_ASSERT(_Extent == distance(__f, __l), "size mismatch in span's constructor (ptr, ptr)"); } _LIBCPP_INLINE_VISIBILITY constexpr span(element_type (&__arr)[_Extent]) noexcept : __data{__arr} {} - _LIBCPP_INLINE_VISIBILITY constexpr span( array<value_type, _Extent>& __arr) noexcept : __data{__arr.data()} {} - _LIBCPP_INLINE_VISIBILITY constexpr span(const array<value_type, _Extent>& __arr) noexcept : __data{__arr.data()} {} + + template <class _OtherElementType, + enable_if_t<is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr> + _LIBCPP_INLINE_VISIBILITY + constexpr span(array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} + + template <class _OtherElementType, + enable_if_t<is_convertible_v<const _OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr> + _LIBCPP_INLINE_VISIBILITY + constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {} template <class _Container> _LIBCPP_INLINE_VISIBILITY @@ -386,13 +394,15 @@ _LIBCPP_INLINE_VISIBILITY constexpr span(element_type (&__arr)[_Sz]) noexcept : __data{__arr}, __size{_Sz} {} - template <size_t _Sz> + template <class _OtherElementType, size_t _Sz, + enable_if_t<is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY - constexpr span(array<value_type, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} + constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} - template <size_t _Sz> + template <class _OtherElementType, size_t _Sz, + enable_if_t<is_convertible_v<const _OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr> _LIBCPP_INLINE_VISIBILITY - constexpr span(const array<value_type, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} + constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {} template <class _Container> _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp b/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp --- a/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp +++ b/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp @@ -68,49 +68,58 @@ } } +template <typename T, typename U = T> +constexpr bool testConstructorArray() +{ + std::array<U,2> val = { U(), U() }; + ASSERT_NOEXCEPT(std::span<T> {val}); + ASSERT_NOEXCEPT(std::span<T, 2>{val}); + std::span<T> s1{val}; + std::span<T, 2> s2{val}; + return s1.data() == &val[0] && s1.size() == 2 + && s2.data() == &val[0] && s2.size() == 2; +} -template <typename T> -constexpr bool testConstexprSpan() +template <typename T, typename U = T> +constexpr bool testConstructorConstArray() { - constexpr std::array<T,2> val = { T(), T() }; + const std::array<U,2> val = { U(), U() }; ASSERT_NOEXCEPT(std::span<const T> {val}); ASSERT_NOEXCEPT(std::span<const T, 2>{val}); std::span<const T> s1{val}; std::span<const T, 2> s2{val}; - return - s1.data() == &val[0] && s1.size() == 2 - && s2.data() == &val[0] && s2.size() == 2; + return s1.data() == &val[0] && s1.size() == 2 + && s2.data() == &val[0] && s2.size() == 2; } - template <typename T> -void testRuntimeSpan() -{ - std::array<T,2> val; - ASSERT_NOEXCEPT(std::span<T> {val}); - ASSERT_NOEXCEPT(std::span<T, 2>{val}); - std::span<T> s1{val}; - std::span<T, 2> s2{val}; - assert(s1.data() == &val[0] && s1.size() == 2); - assert(s2.data() == &val[0] && s2.size() == 2); +constexpr bool testConstructors() { + static_assert(testConstructorArray<T>(), ""); + static_assert(testConstructorArray<const T, T>(), ""); + static_assert(testConstructorConstArray<T>(), ""); + static_assert(testConstructorConstArray<const T, T>(), ""); + + return testConstructorArray<T>() + && testConstructorArray<const T, T>() + && testConstructorConstArray<T>() + && testConstructorConstArray<const T, T>(); } struct A{}; int main(int, char**) { - static_assert(testConstexprSpan<int>(), ""); - static_assert(testConstexprSpan<long>(), ""); - static_assert(testConstexprSpan<double>(), ""); - static_assert(testConstexprSpan<A>(), ""); + assert(testConstructors<int>()); + assert(testConstructors<long>()); + assert(testConstructors<double>()); + assert(testConstructors<A>()); - testRuntimeSpan<int>(); - testRuntimeSpan<long>(); - testRuntimeSpan<double>(); - testRuntimeSpan<std::string>(); - testRuntimeSpan<A>(); + assert(testConstructors<int*>()); + assert(testConstructors<int* const>()); + assert(testConstructors<const int*>()); + assert(testConstructors<const int* const>()); checkCV(); - return 0; + return 0; } diff --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html --- a/libcxx/www/cxx2a_status.html +++ b/libcxx/www/cxx2a_status.html @@ -490,7 +490,7 @@ <tr><td><a href="https://wg21.link/LWG3251">3251</a></td><td>Are <tt>std::format</tt> alignment specifiers applied to string arguments?</td><td>Prague</td><td></td></tr> <tr><td><a href="https://wg21.link/LWG3252">3252</a></td><td>Parse locale's aware modifiers for commands are not consistent with POSIX spec</td><td>Prague</td><td></td></tr> <tr><td><a href="https://wg21.link/LWG3254">3254</a></td><td>Strike <tt>stop_token</tt>'s <tt>operator!=</tt></td><td>Prague</td><td></td></tr> - <tr><td><a href="https://wg21.link/LWG3255">3255</a></td><td><tt>span</tt>'s <tt>array</tt> constructor is too strict</td><td>Prague</td><td></td></tr> + <tr><td><a href="https://wg21.link/LWG3255">3255</a></td><td><tt>span</tt>'s <tt>array</tt> constructor is too strict</td><td>Prague</td><td>Complete</td></tr> <tr><td><a href="https://wg21.link/LWG3260">3260</a></td><td><tt>year_month*</tt> arithmetic rejects durations convertible to years</td><td>Prague</td><td></td></tr> <tr><td><a href="https://wg21.link/LWG3262">3262</a></td><td>Formatting of negative durations is not specified</td><td>Prague</td><td></td></tr> <tr><td><a href="https://wg21.link/LWG3264">3264</a></td><td><tt>sized_range</tt> and <tt>ranges::size</tt> redundantly use <tt>disable_sized_range</tt></td><td>Prague</td><td></td></tr>