2

I'd like to be able to pass my custom container this std::span constructor:

template< class R >
explicit(extent != std::dynamic_extent)
constexpr span( R&& range );

What do I need to add to my custom class to make it satisfy the requirements to be able to pass it to the std::span constructor that receives a range?

For example, with std::vector we are able to do this:

std::vector<int> v = {1, 2, 3};
auto span = std::span{v};

I've already added these to my custom class:

Type* begin()
{
    return m_Data;
}

Type* end()
{
    return m_Data + m_Length;
}

const Type* data() const
{
    return m_Data;
}

size_t size() const
{
    return m_Length;
}

...which in turn allowed me to use range-based loops, and std::data(my_container) as well as std::size(my_container). What am I missing to make it so that I can also pass my container to the std::span constructor? Does it require to implement a more complex iterator?

Ken White
  • 123,280
  • 14
  • 225
  • 444
Erunehtar
  • 1,583
  • 1
  • 19
  • 38
  • 3
    Please provide a [mcve], that includes your entire type. Also the span constructor in question lists its constraints. Did you check those? – Barry Sep 23 '21 at 02:47
  • I did look at the constraints, but I am puzzled to understand them. – Erunehtar Sep 23 '21 at 03:01

1 Answers1

7

This is because your Container does not satisfy contiguous_range, which is defined as:

template<class T>
  concept contiguous_­range =
    random_­access_­range<T> && contiguous_­iterator<iterator_t<T>> &&
    requires(T& t) {
      { ranges::data(t) } -> same_­as<add_pointer_t<range_reference_t<T>>>;
    };

In the requires clause, the return type of ranges::data(t) is const Type*, which is different from add_pointer_t<range_reference_t<T>> that is Type*.

The workaround is adding a non-const data() to your Container which return Type*:

Type* data()  { return m_Data; }
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • Indeed this was my issue. Does that mean std containers implement both const and non-const versions? I guess so. – Erunehtar Sep 23 '21 at 03:08
  • @Deathicon. Not necessarily. Take `string_view` as an example, it only has one `data() const` that returns `const char*`, but since it also has only one `begin() const` and `end() const` that return `const char*`, this also makes it models `contiguous_range`. – 康桓瑋 Sep 23 '21 at 03:14