diff --git a/include/gsl/span b/include/gsl/span index e326446..89574b2 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -343,15 +343,9 @@ namespace details constexpr extent_type() noexcept = default; - template - constexpr extent_type(extent_type ext) - { - static_assert(Other == Ext, - "Mismatch between fixed-size extent and size of initializing data."); - Expects(ext.size() == Ext); - } + constexpr explicit extent_type(extent_type); - constexpr extent_type(size_type size) { Expects(size == Ext); } + constexpr explicit extent_type(size_type size) { Expects(size == Ext); } constexpr size_type size() const noexcept { return Ext; } }; @@ -363,10 +357,10 @@ namespace details using size_type = std::size_t; template - explicit constexpr extent_type(extent_type ext) : size_(ext.size()) + constexpr explicit extent_type(extent_type ext) : size_(ext.size()) {} - explicit constexpr extent_type(size_type size) : size_(size) + constexpr explicit extent_type(size_type size) : size_(size) { Expects(size != dynamic_extent); } @@ -377,6 +371,12 @@ namespace details size_type size_; }; + template + constexpr extent_type::extent_type(extent_type ext) + { + Expects(ext.size() == Ext); + } + template struct calculate_subspan_type { @@ -420,18 +420,28 @@ public: constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) {} - constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count) + template = 0> + constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count) { - if (Extent != dynamic_extent) Expects(count == Extent); + Expects(count == Extent); } - constexpr span(pointer firstElem, pointer lastElem) noexcept + template = 0> + constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count) + {} + + template = 0> + constexpr explicit span(pointer firstElem, pointer lastElem) noexcept : storage_(firstElem, static_cast(lastElem - firstElem)) { - if (Extent != dynamic_extent) - { Expects(lastElem - firstElem == static_cast(Extent)); } + Expects(lastElem - firstElem == static_cast(Extent)); } + template = 0> + constexpr span(pointer firstElem, pointer lastElem) noexcept + : storage_(firstElem, static_cast(lastElem - firstElem)) + {} + template ::value, int> = 0> constexpr span(element_type (&arr)[N]) noexcept @@ -456,40 +466,74 @@ public: : storage_(KnownNotNull{arr.data()}, details::extent_type()) {} - // NB: the SFINAE here uses .data() as an incomplete/imperfect proxy for the requirement - // on Container to be a contiguous sequence container. - template ::value && !details::is_std_array::value && std::is_pointer().data())>::value && std::is_convertible< std::remove_pointer_t().data())> (*)[], - element_type (*)[]>::value>> + element_type (*)[]>::value, int> = 0> + constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size()) + {} + + template ::value && !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible< + std::remove_pointer_t().data())> (*)[], + element_type (*)[]>::value, int> = 0> constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) {} - template ::value && !details::is_span::value && !details::is_std_array::value && std::is_pointer().data())>::value && std::is_convertible().data())> (*)[], - element_type (*)[]>::value>> + decltype(std::declval().data())> (*)[], + element_type (*)[]>::value, int> = 0> + constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size()) + {} + + template ::value && !details::is_span::value && + !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible().data())> (*)[], + element_type (*)[]>::value, int> = 0> constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) {} constexpr span(const span& other) noexcept = default; template < - class OtherElementType, std::size_t OtherExtent, - class = std::enable_if_t< - details::is_allowed_extent_conversion::value && - details::is_allowed_element_type_conversion::value>> + class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent, + std::enable_if_t< + (MyExtent == dynamic_extent || MyExtent == OtherExtent) && + details::is_allowed_element_type_conversion::value, int> = 0> constexpr span(const span& other) noexcept : storage_(other.data(), details::extent_type(other.size())) {} + template < + class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent, + std::enable_if_t< + MyExtent != dynamic_extent && OtherExtent == dynamic_extent && + details::is_allowed_element_type_conversion::value, int> = 0> + constexpr explicit span(const span& other) noexcept + : storage_(other.data(), details::extent_type(other.size())) + {} + ~span() noexcept = default; constexpr span& operator=(const span& other) noexcept = default; @@ -498,7 +542,7 @@ public: constexpr span first() const noexcept { Expects(Count <= size()); - return {data(), Count}; + return span{data(), Count}; } template @@ -508,7 +552,7 @@ public: constexpr span last() const noexcept { Expects(Count <= size()); - return {data() + (size() - Count), Count}; + return span{data() + (size() - Count), Count}; } template @@ -519,8 +563,8 @@ public: typename details::calculate_subspan_type::type { Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); - - return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; + using type = typename details::calculate_subspan_type::type; + return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; } constexpr span first(size_type count) const noexcept @@ -728,10 +772,12 @@ template span::value> as_bytes(span s) noexcept { + using type = span::value>; + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute // clang-format on - return {reinterpret_cast(s.data()), s.size_bytes()}; + return type{reinterpret_cast(s.data()), s.size_bytes()}; } template ::value> as_writable_bytes(span s) noexcept { + using type = span::value>; + // clang-format off GSL_SUPPRESS(type.1) // NO-FORMAT: attribute // clang-format on - return {reinterpret_cast(s.data()), s.size_bytes()}; + return type{reinterpret_cast(s.data()), s.size_bytes()}; } } // namespace gsl diff --git a/include/gsl/string_span b/include/gsl/string_span index b96c9ff..17df7fb 100644 --- a/include/gsl/string_span +++ b/include/gsl/string_span @@ -308,7 +308,7 @@ public: private: static impl_type remove_z(pointer const& sz, std::size_t max) { - return {sz, details::string_length(sz, max)}; + return impl_type(sz, details::string_length(sz, max)); } template diff --git a/tests/span_compatibility_tests.cpp b/tests/span_compatibility_tests.cpp index bebfb77..5035687 100644 --- a/tests/span_compatibility_tests.cpp +++ b/tests/span_compatibility_tests.cpp @@ -846,8 +846,6 @@ static_assert(!std::is_constructible, std::array&>:: "!std::is_constructible, std::array&>"); static_assert(!std::is_constructible, const std::array&>::value, "!std::is_constructible, const std::array&>"); -static_assert(!std::is_constructible, const gsl::span&>::value, - "!std::is_constructible, const gsl::span&>"); static_assert(!std::is_constructible, const gsl::span&>::value, "!std::is_constructible, const gsl::span&>"); static_assert(!std::is_constructible, const gsl::span&>::value, @@ -866,12 +864,8 @@ static_assert(!std::is_constructible, std::array static_assert(!std::is_constructible, const gsl::span&>::value, "!std::is_constructible, const gsl::span&>"); -static_assert(!std::is_constructible, const gsl::span&>::value, - "!std::is_constructible, const gsl::span&>"); static_assert(!std::is_constructible, const gsl::span&>::value, "!std::is_constructible, const gsl::span&>"); -static_assert(!std::is_constructible, const gsl::span&>::value, - "!std::is_constructible, const gsl::span&>"); static_assert( !std::is_constructible, const gsl::span&>::value, "!std::is_constructible, const gsl::span&>"); @@ -925,6 +919,14 @@ static_assert(!std::is_constructible, std::array, const std::array&>::value, "!std::is_constructible, const std::array&>"); +// Explicit construction enabled in P1976R2 +static_assert(std::is_constructible, const gsl::span&>::value, + "std::is_constructible, const gsl::span&>"); +static_assert(std::is_constructible, const gsl::span&>::value, + "std::is_constructible, const gsl::span&>"); +static_assert(std::is_constructible, const gsl::span&>::value, + "std::is_constructible, const gsl::span&>"); + // no throw copy constructor static_assert(std::is_nothrow_copy_constructible>::value, "std::is_nothrow_copy_constructible>"); diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index c5d978e..ce881ba 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -1144,7 +1144,7 @@ TEST(span_test, from_array_constructor) // you can convert statically { - const span s2 = {&arr[0], 2}; + const span s2{&arr[0], 2}; static_cast(s2); } { @@ -1180,7 +1180,7 @@ TEST(span_test, from_array_constructor) #endif { auto f = [&]() { - const span _s4 = {arr2, 2}; + const span _s4{arr2, 2}; static_cast(_s4); }; EXPECT_DEATH(f(), deathstring);