Improved conformance of gsl::span for compile-time errors

as per 23.7.2.1:
- span() and span(nullptr) can only be used if extent is dynamic or 0
- span( element_type(&arr)[N] ) can only be used if extent is dynamic or N
- std::array can be used for initialization if extent is dynamic or size of the array
- Containers can be used for initialization if pointer type is convertible

as per 23.7.2.2
- first<N> and last<N> may no longer exceed the span extents
This commit is contained in:
Jeroen Akershoek 2017-12-05 23:42:12 +02:00
parent 9d65e74400
commit cdd9ee5a6a
2 changed files with 24 additions and 12 deletions

View File

@ -342,6 +342,7 @@ public:
{ {
} }
template <class = std::enable_if_t<Extent == dynamic_extent || Extent == 0>>
constexpr span(std::nullptr_t) GSL_NOEXCEPT : span() {} constexpr span(std::nullptr_t) GSL_NOEXCEPT : span() {}
constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {} constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
@ -351,19 +352,28 @@ public:
{ {
} }
template <std::size_t N> template <std::size_t N, class = std::enable_if_t<extent == dynamic_extent || N == extent>>
constexpr span(element_type (&arr)[N]) GSL_NOEXCEPT constexpr span(element_type (&arr)[N]) GSL_NOEXCEPT
: storage_(&arr[0], details::extent_type<N>()) : storage_(&arr[0], details::extent_type<N>())
{ {
} }
template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>> template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>,
constexpr span(std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT class = std::enable_if_t<
( extent == dynamic_extent || N == extent ) &&
std::is_convertible_v<std::add_pointer_t<ArrayElementType>, pointer>
>>
constexpr span( std::array<ArrayElementType, N>& arr )
: storage_(&arr[0], details::extent_type<N>()) : storage_(&arr[0], details::extent_type<N>())
{ {
} }
template <std::size_t N> template <std::size_t N,
class = std::enable_if_t<
( extent == dynamic_extent || N == extent ) &&
std::is_const_v<element_type> &&
std::is_convertible_v<std::add_pointer_t<element_type>, pointer>
>>
constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) GSL_NOEXCEPT constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) GSL_NOEXCEPT
: storage_(&arr[0], details::extent_type<N>()) : storage_(&arr[0], details::extent_type<N>())
{ {
@ -387,9 +397,7 @@ public:
template <class Container, template <class Container,
class = std::enable_if_t< class = std::enable_if_t<
!details::is_span<Container>::value && !details::is_std_array<Container>::value && !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
std::is_convertible<typename Container::pointer, pointer>::value && std::is_convertible<decltype(std::declval<Container>().data()), pointer>::value>>
std::is_convertible<typename Container::pointer,
decltype(std::declval<Container>().data())>::value>>
constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size())) constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
{ {
} }
@ -397,9 +405,8 @@ public:
template <class Container, template <class Container,
class = std::enable_if_t< class = std::enable_if_t<
std::is_const<element_type>::value && !details::is_span<Container>::value && std::is_const<element_type>::value && !details::is_span<Container>::value &&
std::is_convertible<typename Container::pointer, pointer>::value && !details::is_std_array<Container>::value &&
std::is_convertible<typename Container::pointer, std::is_convertible<decltype(std::declval<Container>().data()), pointer>::value>>
decltype(std::declval<Container>().data())>::value>>
constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size())) constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
{ {
} }
@ -433,14 +440,18 @@ public:
constexpr span& operator=(span&& other) GSL_NOEXCEPT = default; constexpr span& operator=(span&& other) GSL_NOEXCEPT = default;
// [span.sub], span subviews // [span.sub], span subviews
template <std::ptrdiff_t Count> template <std::ptrdiff_t Count,
class = std::enable_if_t<
Count >= 0 && ( extent == dynamic_extent || Count <= extent )>>
constexpr span<element_type, Count> first() const constexpr span<element_type, Count> first() const
{ {
Expects(Count >= 0 && Count <= size()); Expects(Count >= 0 && Count <= size());
return {data(), Count}; return {data(), Count};
} }
template <std::ptrdiff_t Count> template <std::ptrdiff_t Count,
class = std::enable_if_t<
Count >= 0 && ( extent == dynamic_extent || Count <= extent )>>
constexpr span<element_type, Count> last() const constexpr span<element_type, Count> last() const
{ {
Expects(Count >= 0 && size() - Count >= 0); Expects(Count >= 0 && size() - Count >= 0);

View File

@ -23,6 +23,7 @@
#include <array> // for array #include <array> // for array
#include <iostream> // for ptrdiff_t #include <iostream> // for ptrdiff_t
#include <iterator> // for reverse_iterator, operator-, operator== #include <iterator> // for reverse_iterator, operator-, operator==
#include <map> // for std::map
#include <memory> // for unique_ptr, shared_ptr, make_unique, allo... #include <memory> // for unique_ptr, shared_ptr, make_unique, allo...
#include <regex> // for match_results, sub_match, match_results<>... #include <regex> // for match_results, sub_match, match_results<>...
#include <stddef.h> // for ptrdiff_t #include <stddef.h> // for ptrdiff_t