I used to work with gsl::span from the Guidelines Support Library for some time. With gsl::span, is was possible to define a function taking a static extent and calling it with a gsl::span of dynamic extent, e.g.
void f(gsl::span<int, 5> s) { }
...
std::vector<int> v(100);
f(gsl::make_span(v).subspan(42, 5)); // Works
After porting the code to std::span, I noticed that this is no longer possible:
void f(std::span<int, 5> s) { }
...
std::vector<int> v(100);
f(std::span(v).subspan(42, 5)); // Does not work
Is there any reason for this difference? Is there any recommended way to convert a std::span with dynamic extent to a std::span with fixed extent? Of course, it is possible to create a new span with fixed extent when calling the function:
f(std::span<int, 5>(&v[42], 5));
However, I think that the "subspan" variant is much better readable, it expresses the intention in a better way, and it allows appropriate range checking in a debug build.
Is there any reason for this difference?
P1976 goes through this at length. Fixed-extent spans have explicit constructors on purpose to try to alleviate undefined behavior, so std::span<int>
(the type of std::span(v).subspan(42, 5)
) is not convertible to std::span<int, 5>
.
Is there any recommended way to convert a std::span with dynamic extent to a std::span with fixed extent?
If both the offset and the count are constant expressions (which is true in this case), you can use the other overload of subspan()
:
f(std::span(v).subspan<42, 5>());
This overload exists the way it does so that you can take fixed-extent subspans of fixed-extent spans safely, but is less than ideally useful when wanting to take fixed-extent subspans of a dynamic-extent span, where ideally we'd just have wanted std::span(v).subspan<5>(42)
.
For that case, you can instead use first()
in conjunction with subspan
:
f(std::span(v).subspan(42).first<5>());
Slightly longer, but gets the job done.
Or you can go full out and use the constructor:
f(std::span<int, 5>(std::span(v).subspan(42, 5)));
f(std::span<int, 5>(v.data() + 42, 5));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With