I'd like to generalize my code to take std::span
rather than std::vector
as parameter, but without losing the convenience of the auto-conversion you get when passing in a std::vector
(see How can std::vector be converted to std::span?).
However, the functions in question are templated on the element type -- and I get a compile fail on use_span_t
, below.
void use_span(std::span<const double>) {}
template <typename T>
void use_span_t(std::span<const T>)
{
}
const std::vector<double> v{1, 2, 3};
use_span(v); // ok
use_span_t(v); // candidate template ignored: could not match 'span' against 'vector' (clang16)
use_span_t<double>(v); // ok
What am I doing wrong, and is there a workaround which doesn't involve explicit types at the callsite (use_span_t<double>
), or something like the following at the called site.
template <typename T>
void use_span_t(const std::vector<T>& v)
{
use_span_t(v);
}
This function template is basically useless:
template <typename T>
void use_span_t(std::span<const T>);
Because not only does it not accept a vector<double>
or vector<double> const
as you've seen, it doesn't even accept a span<double>
. It accepts, precisely, a span<double const>
. Which is highly limited. It'd be very nice if there were a way for this to work, but...
Until then, if what you want to do is deduce T
for any contiguous range and get a span over T const
over that, you'll have to do it this way:
template <typename T>
void f(std::span<const T>);
template <std::ranges::contiguous_range R>
requires std::ranges::sized_range<R>
void f(R&& r) {
f(std::span<const std::ranges::range_value_t<R>>(r));
}
Any contiguous
+ sized
is convertible to span
, we just have to do it explicitly. range_value_t<R>
gives us the value type (which is double
for both vector<double>
and const vector<double>
), so we can use that to construct the correct span
.
If we called f
with a span<T const>
already, the first overload would be chosen. Anything else, including span<T>
(for non-const
T
), would pick the second which would then forward to the first.
I also wrote a post about coercing deep const-ness almost exactly two years ago now.