13

Consider a large memory container. In this simple example an std::vector<int>:

std::vector v = { 0, 1, 2, 3, 4, 5 };

std::span allows me create a lightweight view over the memory. Now I want to simply print the span:

template<typename T>
void print(std::span<T> span) {
    std::cout << '[';
    if (span.size())
        std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));

    std::cout << span.back() << "]\n";
}

int main() {
    std::vector v = { 0, 1, 2, 3, 4, 5 };

    print(std::span{ v });
}

output:

[0, 1, 2, 3, 4, 5]

now I want to make subsets (which is where the std::span actually becomes useful as a view). I can use iterators to specify my range and call this constructor(3) from std::span

template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );

But that doesn't work:

print(std::span{ v.begin() + 2, v.end() }); //error E0289

C++ no instance of constructor matches the argument list argument types are: (std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>, std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>)


there is the possibility of using the constructor(2) which takes a pointer and size:

print(std::span{ v.data() + 1, 3 }); //-> prints [1, 2, 3]

But that defeats the purpose of iterators.

How can I construct an std::span using iterators? Am I missing something?


full code:

#include <iostream>
#include <vector>
#include <span>
#include <algorithm>

template<typename T>
void print(std::span<T> span) {
    std::cout << '[';
    if (span.size())
        std::copy(span.begin(), span.end() - 1, std::ostream_iterator<int>(std::cout, ", "));

    std::cout << span.back() << "]\n";
}

int main() {
    std::vector v = { 0, 1, 2, 3, 4, 5 };

    print(std::span{ v.begin() + 2, v.end() });
}

until MSVC has implemented the constructor I will be using this make_span function:

template<typename It>
constexpr auto make_span(It begin, It end) {
    return std::span<std::remove_pointer_t<It::pointer>>(&(*begin), std::distance(begin, end));
}

Using Visual Studio Community 2019 Version 16.7.5. Configuration: x64, Release. C++ Language Standard = /std:c++latest

1
  • 2
    I'd blame an outdated standard library (this all very new, after all), given that GCC's is fine with it. LLVM's looks like it might also need a minute. Godbolt Commented Oct 3, 2020 at 17:55

1 Answer 1

12

You can construct a span using iterators, it has such a constructor (as added by P1394, which you can see in [views.span]):

template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );

It's just that MSVC's standard library doesn't implement it. The program compiles fine on gcc, as expected.

Sign up to request clarification or add additional context in comments.

1 Comment

That makes a lot more sense now, I am just confused why they are partially implementing constructors. Guess I will have to reside on a custom make_span(first, last) for now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.