diff --git a/libcxx/include/span b/libcxx/include/span --- a/libcxx/include/span +++ b/libcxx/include/span @@ -214,15 +214,31 @@ constexpr span (const span&) noexcept = default; constexpr span& operator=(const span&) noexcept = default; - _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __ptr, size_type __count) : __data{__ptr} + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(pointer __ptr, size_type __count) : __data{__ptr} { (void)__count; _LIBCPP_ASSERT(_Extent == __count, "size mismatch in span's constructor (ptr, len)"); } - _LIBCPP_INLINE_VISIBILITY constexpr span(pointer __f, pointer __l) : __data{__f} + _LIBCPP_INLINE_VISIBILITY constexpr explicit span(pointer __f, pointer __l) : __data{__f} { (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& __arr) noexcept : __data{__arr.data()} {} _LIBCPP_INLINE_VISIBILITY constexpr span(const array& __arr) noexcept : __data{__arr.data()} {} + template + _LIBCPP_INLINE_VISIBILITY + constexpr span( _Container& __c, + enable_if_t<__is_span_compatible_container<_Container, _Tp>::value, nullptr_t> = nullptr) + : __data{_VSTD::data(__c)} { + _LIBCPP_ASSERT(_Extent == _VSTD::size(__c), "size mismatch in span's constructor (range)"); + } + + template + _LIBCPP_INLINE_VISIBILITY + constexpr span(const _Container& __c, + enable_if_t<__is_span_compatible_container::value, nullptr_t> = nullptr) + : __data{_VSTD::data(__c)} { + _LIBCPP_ASSERT(_Extent == _VSTD::size(__c), "size mismatch in span's constructor (range)"); + } + template _LIBCPP_INLINE_VISIBILITY constexpr span(const span<_OtherElementType, _Extent>& __other, @@ -233,7 +249,7 @@ template _LIBCPP_INLINE_VISIBILITY - constexpr span(const span<_OtherElementType, dynamic_extent>& __other, + constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other, enable_if_t< is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr) noexcept @@ -247,7 +263,7 @@ constexpr span first() const noexcept { static_assert(_Count <= _Extent, "Count out of range in span::first()"); - return {data(), _Count}; + return span{data(), _Count}; } template @@ -255,7 +271,7 @@ constexpr span last() const noexcept { static_assert(_Count <= _Extent, "Count out of range in span::last()"); - return {data() + size() - _Count, _Count}; + return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY @@ -278,7 +294,8 @@ -> span { static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()"); - return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; + using _ReturnType = span; + return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } @@ -336,10 +353,10 @@ } _LIBCPP_INLINE_VISIBILITY span __as_bytes() const noexcept - { return {reinterpret_cast(data()), size_bytes()}; } + { return span{reinterpret_cast(data()), size_bytes()}; } _LIBCPP_INLINE_VISIBILITY span __as_writable_bytes() const noexcept - { return {reinterpret_cast(data()), size_bytes()}; } + { return span{reinterpret_cast(data()), size_bytes()}; } private: pointer __data; @@ -417,7 +434,7 @@ constexpr span first() const noexcept { _LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::first()"); - return {data(), _Count}; + return span{data(), _Count}; } template @@ -425,7 +442,7 @@ constexpr span last() const noexcept { _LIBCPP_ASSERT(_Count <= size(), "Count out of range in span::last()"); - return {data() + size() - _Count, _Count}; + return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY @@ -448,7 +465,7 @@ { _LIBCPP_ASSERT(_Offset <= size(), "Offset out of range in span::subspan()"); _LIBCPP_ASSERT(_Count == dynamic_extent || _Offset + _Count <= size(), "Count out of range in span::subspan()"); - return {data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; + return span{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } constexpr span diff --git a/libcxx/test/std/containers/views/span.cons/assign.pass.cpp b/libcxx/test/std/containers/views/span.cons/assign.pass.cpp --- a/libcxx/test/std/containers/views/span.cons/assign.pass.cpp +++ b/libcxx/test/std/containers/views/span.cons/assign.pass.cpp @@ -185,13 +185,14 @@ // constexpr statically sized assignment { - constexpr std::span spans[] = { - {carr1, 2}, - {carr1 + 1, 2}, - {carr1 + 2, 2}, - {carr2, 2}, - {carr2 + 1, 2}, - {carr3, 2} + using spanType = std::span; + constexpr spanType spans[] = { + spanType{carr1, 2}, + spanType{carr1 + 1, 2}, + spanType{carr1 + 2, 2}, + spanType{carr2, 2}, + spanType{carr2 + 1, 2}, + spanType{carr3, 2} }; static_assert(std::size(spans) == 6, "" ); @@ -247,10 +248,11 @@ // statically sized assignment { - std::span spans[] = { - {arr, arr + 2}, - {arr + 1, arr + 3}, - {arr + 2, arr + 4} + using spanType = std::span; + spanType spans[] = { + spanType{arr, arr + 2}, + spanType{arr + 1, arr + 3}, + spanType{arr + 2, arr + 4} }; for (size_t i = 0; i < std::size(spans); ++i) @@ -279,10 +281,11 @@ } { - std::span spans[] = { - {strs, strs + 1}, - {strs + 1, strs + 2}, - {strs + 2, strs + 3} + using spanType = std::span; + spanType spans[] = { + spanType{strs, strs + 1}, + spanType{strs + 1, strs + 2}, + spanType{strs + 2, strs + 3} }; for (size_t i = 0; i < std::size(spans); ++i) diff --git a/libcxx/test/std/containers/views/span.cons/container.fail.cpp b/libcxx/test/std/containers/views/span.cons/container.fail.cpp --- a/libcxx/test/std/containers/views/span.cons/container.fail.cpp +++ b/libcxx/test/std/containers/views/span.cons/container.fail.cpp @@ -106,12 +106,5 @@ std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'std::span'}} } -// statically sized - { - IsAContainer c; - std::span s1{c}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - - return 0; } diff --git a/libcxx/test/std/containers/views/span.cons/container.pass.cpp b/libcxx/test/std/containers/views/span.cons/container.pass.cpp --- a/libcxx/test/std/containers/views/span.cons/container.pass.cpp +++ b/libcxx/test/std/containers/views/span.cons/container.pass.cpp @@ -84,14 +84,32 @@ return s1.data() == val.getV() && s1.size() == 1; } +template +constexpr bool testConstexprSpanStatic() +{ + constexpr IsAContainer val{}; + std::span s1{val}; + return s1.data() == val.getV() && s1.size() == 1; +} template void testRuntimeSpan() { IsAContainer val{}; const IsAContainer cVal; - std::span s1{val}; - std::span s2{cVal}; + std::span s1{val}; + std::span s2{cVal}; + assert(s1.data() == val.getV() && s1.size() == 1); + assert(s2.data() == cVal.getV() && s2.size() == 1); +} + +template +void testRuntimeSpanStatic() +{ + IsAContainer val{}; + const IsAContainer cVal; + std::span s1{val}; + std::span s2{cVal}; assert(s1.data() == val.getV() && s1.size() == 1); assert(s2.data() == cVal.getV() && s2.size() == 1); } @@ -105,12 +123,23 @@ static_assert(testConstexprSpan(), ""); static_assert(testConstexprSpan(), ""); + static_assert(testConstexprSpanStatic(), ""); + static_assert(testConstexprSpanStatic(), ""); + static_assert(testConstexprSpanStatic(), ""); + static_assert(testConstexprSpanStatic(), ""); + testRuntimeSpan(); testRuntimeSpan(); testRuntimeSpan(); testRuntimeSpan(); testRuntimeSpan(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + testRuntimeSpanStatic(); + checkCV(); return 0;