|
constexpr | Span () noexcept |
|
template<typename T , typename std::enable_if< std::is_convertible< T(*)[], C(*)[]>::value, int >::type = 0> |
constexpr | Span (T *begin, std::size_t size) noexcept |
| Construct a span from a begin pointer and a size.
|
|
template<typename T , typename std::enable_if< std::is_convertible< T(*)[], C(*)[]>::value, int >::type = 0> |
CONSTEXPR_IF_NOT_DEBUG | Span (T *begin, T *end) noexcept |
| Construct a span from a begin and end pointer.
|
|
template<typename O , typename std::enable_if< std::is_convertible< O(*)[], C(*)[]>::value, int >::type = 0> |
constexpr | Span (const Span< O > &other) noexcept |
| Implicit conversion of spans between compatible types.
|
|
constexpr | Span (const Span &) noexcept=default |
| Default copy constructor.
|
|
Span & | operator= (const Span &other) noexcept=default |
| Default assignment operator.
|
|
template<int N> |
constexpr | Span (C(&a)[N]) noexcept |
| Construct a Span from an array.
|
|
template<typename V > |
constexpr | Span (V &other SPAN_ATTR_LIFETIMEBOUND, typename std::enable_if< !is_Span< 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, std::nullptr_t >::type=nullptr) |
| Construct a Span for objects with .data() and .size() (std::string, std::array, std::vector, ...).
|
|
template<typename V > |
constexpr | Span (const V &other SPAN_ATTR_LIFETIMEBOUND, typename std::enable_if< !is_Span< V >::value &&std::is_convertible< typename std::remove_pointer< decltype(std::declval< const V & >().data())>::type(*)[], C(*)[]>::value &&std::is_convertible< decltype(std::declval< const V & >().size()), std::size_t >::value, std::nullptr_t >::type=nullptr) |
|
constexpr C * | data () const noexcept |
|
constexpr C * | begin () const noexcept |
|
constexpr C * | end () const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG C & | front () const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG C & | back () const noexcept |
|
constexpr std::size_t | size () const noexcept |
|
constexpr std::size_t | size_bytes () const noexcept |
|
constexpr bool | empty () const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG C & | operator[] (std::size_t pos) const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG Span< C > | subspan (std::size_t offset) const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG Span< C > | subspan (std::size_t offset, std::size_t count) const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG Span< C > | first (std::size_t count) const noexcept |
|
CONSTEXPR_IF_NOT_DEBUG Span< C > | last (std::size_t count) const noexcept |
|
A Span is an object that can refer to a contiguous sequence of objects.
It implements a subset of C++20's std::span.
Things to be aware of when writing code that deals with Spans:
- Similar to references themselves, Spans are subject to reference lifetime issues. The user is responsible for making sure the objects pointed to by a Span live as long as the Span is used. For example:
std::vector<int> vec{1,2,3,4};
Span<int> sp(vec);
vec.push_back(5);
printf("%i\n", sp.front()); // UB!
may exhibit undefined behavior, as increasing the size of a vector may invalidate references.
- One particular pitfall is that Spans can be constructed from temporaries, but this is unsafe when the Span is stored in a variable, outliving the temporary. For example, this will compile, but exhibits undefined behavior:
Span<const int> sp(std::vector<int>{1, 2, 3});
printf("%i\n", sp.front()); // UB!
The lifetime of the vector ends when the statement it is created in ends. Thus the Span is left with a dangling reference, and using it is undefined.
Due to Span's automatic creation from range-like objects (arrays, and data types that expose a data() and size() member function), functions that accept a Span as input parameter can be called with any compatible range-like object. For example, this works:
void Foo(Span<const int> arg);
Foo(std::vector<int>{1, 2, 3}); // Works
This is very useful in cases where a function truly does not care about the container, and only about having exactly a range of elements. However it may also be surprising to see automatic conversions in this case.
When a function accepts a Span with a mutable element type, it will not accept temporaries; only variables or other references. For example:
void FooMut(Span<int> arg);
FooMut(std::vector<int>{1, 2, 3}); // Does not compile
std::vector<int> baz{1, 2, 3};
FooMut(baz); // Works
This is similar to how functions that take (non-const) lvalue references as input cannot accept temporaries. This does not work either:
void FooVec(std::vector<int>& arg);
FooVec(std::vector<int>{1, 2, 3}); // Does not compile
The idea is that if a function accepts a mutable reference, a meaningful result will be present in that variable after the call. Passing a temporary is useless in that context.
Definition at line 93 of file span.h.
Implicit conversion of spans between compatible types.
Specifically, if a pointer to an array of type O can be implicitly converted to a pointer to an array of type C, then permit implicit conversion of Span<O> to Span<C>. This matches the behavior of the corresponding C++20 std::span constructor.
For example this means that a Span<T> can be converted into a Span<const
T>.
Definition at line 145 of file span.h.
Construct a Span for objects with .data() and .size() (std::string, std::array, std::vector, ...).
This implements a subset of the functionality provided by the C++20 std::span range-based constructor.
To prevent surprises, only Spans for constant value types are supported when passing in temporaries. Note that this restriction does not exist when converting arrays or other Spans (see above).
Definition at line 171 of file span.h.