Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why can't I construct an std::span from iterators?

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

like image 952
Stack Danny Avatar asked Oct 03 '20 17:10

Stack Danny


People also ask

What is span c++?

A span provides a safe way to iterate over and index into objects that are arranged back-to-back in memory. Such as objects stored in a built-in array, std::array , or std::vector . If you typically access a sequence of back-to-back objects using a pointer and an index, a span is a safer, lightweight alternative.

What is GSL span?

gsl::span is a replacement for (pointer, length) pairs to refer to a sequence of contiguous objects. It can be thought of as a pointer to an array, but that knows its bounds. For example, a span<int,7> refers to a sequence of seven contiguous integers. A span does not own the elements it points to.

How do you compare iterators?

To compare the values that two iterators are pointing at, dereference the iterators first, and then use a comparison operator. Operator= -- Assign the iterator to a new position (typically the start or end of the container's elements).

What is the point of iterators?

The primary purpose of an iterator is to allow a user to process every element of a container while isolating the user from the internal structure of the container. This allows the container to store elements in any manner it wishes while allowing the user to treat it as if it were a simple sequence or list.


1 Answers

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.

like image 88
Barry Avatar answered Oct 24 '22 04:10

Barry