Improve span constructor requirements

Particularly, properly account for the const-ness of the data returned by it.
This commit is contained in:
Chris Robinson
2019-05-30 11:46:48 -07:00
parent 76e7c8b244
commit 1c8dfb55d8
+10 -7
View File
@@ -75,10 +75,12 @@ namespace detail_ {
} // namespace detail_
#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
#define USABLE_CONTAINER_DATA(...) \
std::is_convertible<typename std::remove_pointer<decltype(al::data(std::declval<__VA_ARGS__>()))>::type(*)[],element_type(*)[]>::value
#define IS_VALID_CONTAINER(C) \
!detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
!std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
std::is_convertible<typename std::remove_pointer<decltype(al::data(std::declval<C>()))>::type(*)[],element_type(*)[]>::value
USABLE_CONTAINER_DATA(C&)
template<typename T, size_t E>
class span {
@@ -108,13 +110,13 @@ public:
constexpr span(pointer first, pointer /*last*/) : mData{first} { }
template<size_t N, REQUIRES(extent == N)>
constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
template<size_t N, REQUIRES(extent == N && std::is_convertible<value_type(*)[],element_type(*)[]>::value)>
template<size_t N, REQUIRES(extent == N && USABLE_CONTAINER_DATA(std::array<value_type,N>&))>
constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
template<size_t N, REQUIRES(extent == N && std::is_convertible<value_type(*)[],element_type(*)[]>::value)>
template<size_t N, REQUIRES(extent == N && USABLE_CONTAINER_DATA(const std::array<value_type,N>&))>
constexpr span(const std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
template<typename U, size_t N, REQUIRES(!std::is_same<element_type,U>::value && extent == N && std::is_convertible<U(*)[],element_type(*)[]>::value)>
constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
@@ -202,13 +204,13 @@ public:
constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { }
template<size_t N>
constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
template<size_t N, REQUIRES(std::is_convertible<value_type(*)[],element_type(*)[]>::value)>
template<size_t N, REQUIRES(USABLE_CONTAINER_DATA(std::array<value_type,N>&))>
constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
template<size_t N, REQUIRES(std::is_convertible<value_type(*)[],element_type(*)[]>::value)>
template<size_t N, REQUIRES(USABLE_CONTAINER_DATA(const std::array<value_type,N>&))>
constexpr span(const std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
template<typename U, size_t N, REQUIRES((!std::is_same<element_type,U>::value || extent != N) && std::is_convertible<U(*)[],element_type(*)[]>::value)>
constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
@@ -288,6 +290,7 @@ constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const -> s
}
#undef IS_VALID_CONTAINER
#undef USABLE_CONTAINER_DATA
#undef REQUIRES
} // namespace al