We may come across cases where we need to write a method but we'd like to have the flexibility to accept a plain array or STL containers as input. std::span solves this problem. It gives the user a view into a contiguous sequence of elements. This recipe will teach you how to use it.
Using span
How to do it...
In this recipe, we'll write a method with one parameter (std::span) that can be used in different contexts. Then, we'll highlight the flexibility it offers:
- Let's start by adding the includes we need. Then, we need to define the print method by passing the container variable of the std::span type:
#include <iostream>
#include <vector>
#include <array>
#include <span>
void print(std::span<int> container)
{
for(const auto &c : container)
std::cout << c << "-";
}
- In main, we want to print our arrays by calling the print method:
int main()
{
int elems[]{4, 2, 43, 12};
print(elems);
std::vector vElems{4, 2, 43, 12};
print(vElems);
}
Let's see how this works.
How it works...
std::span describes an object that refers to a contiguous sequence of elements. The C++ standard defines an array as having a contiguous portion of memory. This definitely simplifies the std::span implementation, since a typical one includes a pointer to the first element of the sequence and the size.
Step 1 defines the print method of passing the std::span, which we can read as a sequence of integers. Any array type that has contiguous memory will be seen from the method as a sequence.
Step 2 uses the print method with two different arrays, one C-style and the second an std::vector part of the STL library. Since both arrays are defined in a contiguous portion of memory, std::span is able to seamlessly manage them.
There's more...
Our method considers std::span with the int type. You might need to make the method generic. In this case, you'd need to write something like this:
template <typename T>
void print(std::span<T> container)
{
for(const auto &c : container)
std::cout << c << "-";
}
As we learned in the Understanding concepts recipe, it is wise to specify some requirements in this template. Therefore, we might write to the following:
template <typename T>
requires Integral<T>
void print(std::span<T> container)
{
for(const auto &c : container)
std::cout << c << "-";
}
The requires Integral<T> would make explicit the needs of an Integral type for the template.
See also
- The Understanding concepts recipe to review how to write concepts with templates and apply them to std::span.
- https://gcc.gnu.org/projects/cxx-status.html for a list of C++20 features mapped with GCC versions and their statuses.