Skip to content

Commit ab303a1

Browse files
committed
Add Span constructors for arrays and vectors
1 parent bb3d38f commit ab303a1

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

src/span.h

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ class Span
5656
/** Default assignment operator. */
5757
Span& operator=(const Span& other) noexcept = default;
5858

59+
/** Construct a Span from an array. This matches the corresponding C++20 std::span constructor. */
60+
template <int N>
61+
constexpr Span(C (&a)[N]) noexcept : m_data(a), m_size(N) {}
62+
63+
/** Construct a Span for objects with .data() and .size() (std::string, std::array, std::vector, ...).
64+
*
65+
* This implements a subset of the functionality provided by the C++20 std::span range-based constructor.
66+
*
67+
* To prevent surprises, only Spans for constant value types are supported when passing in temporaries.
68+
* Note that this restriction does not exist when converting arrays or other Spans (see above).
69+
*/
70+
template <typename V, typename std::enable_if<(std::is_const<C>::value || std::is_lvalue_reference<V>::value) && std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, int>::type = 0>
71+
constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {}
72+
5973
constexpr C* data() const noexcept { return m_data; }
6074
constexpr C* begin() const noexcept { return m_data; }
6175
constexpr C* end() const noexcept { return m_data + m_size; }
@@ -79,19 +93,13 @@ class Span
7993
template <typename O> friend class Span;
8094
};
8195

82-
/** Create a span to a container exposing data() and size().
83-
*
84-
* This correctly deals with constness: the returned Span's element type will be
85-
* whatever data() returns a pointer to. If either the passed container is const,
86-
* or its element type is const, the resulting span will have a const element type.
87-
*
88-
* std::span will have a constructor that implements this functionality directly.
89-
*/
90-
template<typename A, int N>
91-
constexpr Span<A> MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
92-
93-
template<typename V>
94-
constexpr Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type> MakeSpan(V& v) { return Span<typename std::remove_pointer<decltype(std::declval<V>().data())>::type>(v.data(), v.size()); }
96+
// MakeSpan helps constructing a Span of the right type automatically.
97+
/** MakeSpan for arrays: */
98+
template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); }
99+
/** MakeSpan for temporaries / rvalue references, only supporting const output. */
100+
template <typename V> constexpr auto MakeSpan(V&& v) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); }
101+
/** MakeSpan for (lvalue) references, supporting mutable output. */
102+
template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; }
95103

96104
/** Pop the last element off a span, and return a reference to that element. */
97105
template <typename T>

0 commit comments

Comments
 (0)