mirror of
https://github.com/AnthonyCalandra/modern-cpp-features.git
synced 2025-12-17 01:54:36 +03:00
Improve the std::span section.
This commit is contained in:
58
CPP20.md
58
CPP20.md
@@ -482,40 +482,48 @@ std::osyncstream{std::cout} << "The value of x is:" << x << std::endl;
|
|||||||
```
|
```
|
||||||
|
|
||||||
### std::span
|
### std::span
|
||||||
A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. Spans can be dynamically-sized or fixed-sized.
|
A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. As opposed to maintaining a pointer/iterator and length field, a span wraps both of those up in a single object.
|
||||||
|
|
||||||
|
Spans can be dynamically-sized or fixed-sized (known as their *extent*). Fixed-sized spans benefit from bounds-checking.
|
||||||
|
|
||||||
|
Span doesn't propogate const so to construct a read-only span use `std::span<const T>`.
|
||||||
|
|
||||||
|
Example: using a dynamically-sized span to print integers from various containers.
|
||||||
```c++
|
```c++
|
||||||
void f(std::span<int> ints) {
|
void print_ints(std::span<const int> ints) {
|
||||||
std::for_each(ints.begin(), ints.end(), [](auto i) {
|
for (const auto n : ints) {
|
||||||
// ...
|
std::cout << n << std::endl;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> v = {1, 2, 3};
|
print_ints(std::vector{ 1, 2, 3 });
|
||||||
f(v);
|
print_ints(std::array<int, 5>{ 1, 2, 3, 4, 5 });
|
||||||
std::array<int, 3> a = {1, 2, 3};
|
|
||||||
f(a);
|
int a[10] = { 0 };
|
||||||
|
print_ints(a);
|
||||||
// etc.
|
// etc.
|
||||||
```
|
```
|
||||||
Example: as opposed to maintaining a pointer and length field, a span wraps both of those up in a single container.
|
|
||||||
|
Example: a statically-sized span will fail to compile for containers that don't match the extent of the span.
|
||||||
```c++
|
```c++
|
||||||
constexpr size_t LENGTH_ELEMENTS = 3;
|
void print_three_ints(std::span<const int, 3> ints) {
|
||||||
int* arr = new int[LENGTH_ELEMENTS]; // arr = {0, 0, 0}
|
for (const auto n : ints) {
|
||||||
|
std::cout << n << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fixed-sized span which provides a view of `arr`.
|
print_three_ints(std::vector{ 1, 2, 3 }); // ERROR
|
||||||
std::span<int, LENGTH_ELEMENTS> span = arr;
|
print_three_ints(std::array<int, 5>{ 1, 2, 3, 4, 5 }); // ERROR
|
||||||
span[1] = 1; // arr = {0, 1, 0}
|
int a[10] = { 0 };
|
||||||
|
print_three_ints(a); // ERROR
|
||||||
|
|
||||||
// Dynamic-sized span which provides a view of `arr`.
|
std::array<int, 3> b = { 1, 2, 3 };
|
||||||
std::span<int> d_span = arr;
|
print_three_ints(b); // OK
|
||||||
span[0] = 1; // arr = {1, 1, 0}
|
|
||||||
```
|
|
||||||
```c++
|
|
||||||
constexpr size_t LENGTH_ELEMENTS = 3;
|
|
||||||
int* arr = new int[LENGTH_ELEMENTS];
|
|
||||||
|
|
||||||
std::span<int, LENGTH_ELEMENTS> span = arr; // OK
|
// You can construct a span manually if required:
|
||||||
std::span<double, LENGTH_ELEMENTS> span2 = arr; // ERROR
|
std::vector c{ 1, 2, 3 };
|
||||||
std::span<int, 1> span3 = arr; // ERROR
|
print_three_ints(std::span<const int, 3>{ c.data(), 3 }); // OK: set pointer and length field.
|
||||||
|
print_three_ints(std::span<const int, 3>{ c.cbegin(), c.cend() }); // OK: use iterator pairs.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Bit operations
|
### Bit operations
|
||||||
|
|||||||
58
README.md
58
README.md
@@ -583,40 +583,48 @@ std::osyncstream{std::cout} << "The value of x is:" << x << std::endl;
|
|||||||
```
|
```
|
||||||
|
|
||||||
### std::span
|
### std::span
|
||||||
A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. Spans can be dynamically-sized or fixed-sized.
|
A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. As opposed to maintaining a pointer/iterator and length field, a span wraps both of those up in a single object.
|
||||||
|
|
||||||
|
Spans can be dynamically-sized or fixed-sized (known as their *extent*). Fixed-sized spans benefit from bounds-checking.
|
||||||
|
|
||||||
|
Span doesn't propogate const so to construct a read-only span use `std::span<const T>`.
|
||||||
|
|
||||||
|
Example: using a dynamically-sized span to print integers from various containers.
|
||||||
```c++
|
```c++
|
||||||
void f(std::span<int> ints) {
|
void print_ints(std::span<const int> ints) {
|
||||||
std::for_each(ints.begin(), ints.end(), [](auto i) {
|
for (const auto n : ints) {
|
||||||
// ...
|
std::cout << n << std::endl;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> v = {1, 2, 3};
|
print_ints(std::vector{ 1, 2, 3 });
|
||||||
f(v);
|
print_ints(std::array<int, 5>{ 1, 2, 3, 4, 5 });
|
||||||
std::array<int, 3> a = {1, 2, 3};
|
|
||||||
f(a);
|
int a[10] = { 0 };
|
||||||
|
print_ints(a);
|
||||||
// etc.
|
// etc.
|
||||||
```
|
```
|
||||||
Example: as opposed to maintaining a pointer and length field, a span wraps both of those up in a single container.
|
|
||||||
|
Example: a statically-sized span will fail to compile for containers that don't match the extent of the span.
|
||||||
```c++
|
```c++
|
||||||
constexpr size_t LENGTH_ELEMENTS = 3;
|
void print_three_ints(std::span<const int, 3> ints) {
|
||||||
int* arr = new int[LENGTH_ELEMENTS]; // arr = {0, 0, 0}
|
for (const auto n : ints) {
|
||||||
|
std::cout << n << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fixed-sized span which provides a view of `arr`.
|
print_three_ints(std::vector{ 1, 2, 3 }); // ERROR
|
||||||
std::span<int, LENGTH_ELEMENTS> span = arr;
|
print_three_ints(std::array<int, 5>{ 1, 2, 3, 4, 5 }); // ERROR
|
||||||
span[1] = 1; // arr = {0, 1, 0}
|
int a[10] = { 0 };
|
||||||
|
print_three_ints(a); // ERROR
|
||||||
|
|
||||||
// Dynamic-sized span which provides a view of `arr`.
|
std::array<int, 3> b = { 1, 2, 3 };
|
||||||
std::span<int> d_span = arr;
|
print_three_ints(b); // OK
|
||||||
span[0] = 1; // arr = {1, 1, 0}
|
|
||||||
```
|
|
||||||
```c++
|
|
||||||
constexpr size_t LENGTH_ELEMENTS = 3;
|
|
||||||
int* arr = new int[LENGTH_ELEMENTS];
|
|
||||||
|
|
||||||
std::span<int, LENGTH_ELEMENTS> span = arr; // OK
|
// You can construct a span manually if required:
|
||||||
std::span<double, LENGTH_ELEMENTS> span2 = arr; // ERROR
|
std::vector c{ 1, 2, 3 };
|
||||||
std::span<int, 1> span3 = arr; // ERROR
|
print_three_ints(std::span<const int, 3>{ c.data(), 3 }); // OK: set pointer and length field.
|
||||||
|
print_three_ints(std::span<const int, 3>{ c.cbegin(), c.cend() }); // OK: use iterator pairs.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Bit operations
|
### Bit operations
|
||||||
|
|||||||
Reference in New Issue
Block a user