Search code examples
c++templatesguideline-support-library

Force gsl::as_span to return a gsl::span<const T>?


Given the following function, taking: a read-only float span (of either dynamic or any static size):

template <long N> void foobar(gsl::span<const float, N> x);

Let's say I have a vector<float>. Passing that as an argument doesn't work, but neither does using gsl::as_span:

std::vector<float> v = {1, 2, 3};
foobar(gsl::as_span(v));

The above does not compile. Apparently gsl::as_span() returns a gsl::span<float>. Besides not understanding why implicit cast to gsl::span<const float> isn't possible, is there a way to force gsl::as_span() to return a read-only span?


Solution

  • Poking around GSL/span.h on the github page you linked to, I found the following overload of as_span that I believe is the one being called here:

    template <typename Cont>
    constexpr auto as_span(Cont& arr) -> std::enable_if_t<
        !details::is_span<std::decay_t<Cont>>::value,
        span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>>
    {
        Expects(arr.size() < PTRDIFF_MAX);
        return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())};
    }
    

    There's lots to digest here, but in particular the return type of this function boils down to span<std::remove_reference<decltype(*arr.data())>, ...>. For your given vector<float> gives span<float,...> because decltype(*arr.data()) is float &. I believe the following should work:

     const auto & cv = v;
     foobar(as_span(cv));
    

    but can't test it myself unfortunately. Let me know if this works.