C++ Core Guidelines promotes the practice of using span
.
The problem is with const and mutable ranges. This is what I tried to do:
auto foo(gsl::span<int>); // 1st
auto foo(gsl::span<const int>); // 2nd
But they can't be called without explicit span
cast/construct of the argument:
std::vector<int> v;
const std::vector<int> cv;
const std::vector<int>& crv = v;
// ambiguous
// want to call 1st
foo(v);
// ambiguous, although 1st is illegal (static_assert kicks in)
// want to call 2nd
foo(cv); // ambiguous
foo(crv); // ambiguous
What is the proper way to deal with this?
This seems like something that should be trivial, analog to const T&
and T&
overloads, yet it isn't (or I just don't see it).
Just to be on the same page, foo(gsl::span<int>{v})
is cumbersome, and I want to avoid it, leave the callers simple: foo(v)
.
I generalized the issue, but just in case this is an XY problem, this is what I actually try to do:
auto split(gsl::cstring_span<> str) -> std::vector<gsl::cstring_span<>>;
auto split(gsl::string_span<> str) -> std::vector<gsl::string_span<>>;
and want to be callable with [const] char *
, [const] string
, etc. arguments.
According to P0122R1 the relevant constructor of the span
class is:
template <class Container>
constexpr span(Container& cont);
So all your 3 examples are unfortunately ill-formed. The second one can be made legal by requiring that this constructor is removed from overload resolution unless the Container::value_type&
is convertible to span::value_type&
Container
is compatible with the span.
Even if we do that, I see no way to allow number 1 and 3, since both overloads require exactly one user-defined implicit conversion.
The usual workaround is to add another level:
template<class T>
auto foo( T && x ) { return foo_impl( as_span(std::forward<T>(x) ) ); }
auto foo_impl(gsl::span<int>); // 1st
auto foo_impl(gsl::span<const int>); // 2nd
Note that as_span
is not in P0122R1, but it is implemented in the Microsoft GSL. It works because it inspects the type and return a span<typename Container::value_type>
.