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:
Because not only does it not accept a
vector<double>orvector<double> constas you've seen, it doesn't even accept aspan<double>. It accepts, precisely, aspan<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
Tfor any contiguous range and get a span overT constover that, you'll have to do it this way:Any
contiguous+sizedis convertible tospan, we just have to do it explicitly.range_value_t<R>gives us the value type (which isdoublefor bothvector<double>andconst vector<double>), so we can use that to construct the correctspan.If we called
fwith aspan<T const>already, the first overload would be chosen. Anything else, includingspan<T>(for non-constT), 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.