Home > Net >  Why can std::vector not accept iota_view vectors of type size_t?
Why can std::vector not accept iota_view vectors of type size_t?

Time:10-20

The following code fails to compile when n is size_t but works fine for int and unsigned.

#include <vector>
#include <ranges>

int main() {
    size_t n = 1;
    auto view = std::ranges::iota_view{n, n};
    std::vector test(view.begin(), view.end()); //std::vector dislikes these itterators
}

https://godbolt.org/z/a3eGeMWqh

CodePudding user response:

In order to solve the issue of integer overflow, the difference type of iota_view<uint64_t, uint64_t>::iterator will be __int128 in libstdc , which is a integer-class type.

An iterator with integer-class difference type is not a C 17 input iterator, so this makes vector template deduction fails because the iterator pair argument does not meet the requirements of __LegacyInputIterator (i.e. the difference type should only be a (signed) integral type).

It's worth noting that __int128 is treated as integral type (which models std::integral) under GNU extensions, your code will be well-formed under the --std=gnu 20 flag.

CodePudding user response:

I suppose it is indeed unspecified whether this deduction is allowed.

The deduction guide that you want to use here requires that the iterator is a (legacy) input iterator. It is (mostly) unspecified to what degree the implementation will verify this. It may or may not check the requirements listed in the standard. See [container.requirements.general]/18 for details.

However one of the requirements is that difference_type is a "signed integer type" (or void), see [iterator.iterators]/2.2.

On the other hand iota_view's iterators are only specified to have a difference_type which is a signed integer type if such a type exists with a width larger than the width of the value type. This is typically not the case for size_t. In this case the standard only requires difference_type to be a "signed-integer-like type". See [range.iota.view]/1 and [sequence.reqmts]/13.3 for details.

A signed-integer-like type may also be a non-integer type that behaves like one. But if a type is chosen that is not actually an integer type, then the iterator doesn't satisfy the legacy iterator requirements and therefore the requirements for the deduction guide would not be fulfilled.

You can inspect std::begin(view)::difference_type to see that GCC chose __int128, which behaves like an integer, but which the implementation doesn't consider an extended integer type (std::is_integral_v<__int128> is false).

GCC still gives the iterator a std::input_iterator_tag as iterator_category member, but going by the resolution of LWG 3670 that is supposed to be removed under these circumstances and that resolution also seems to indicate to me that the iterators of std::iota_view are really not supposed to be guaranteed to be legacy iterators in this situation. I don't know enough about this to be sure whether there is a defect here or not. It seems unfortunate to me if this is intended.

The same applies to the constructor itself as well, so specifying the template argument on std::vector will not resolve this either. See [sequence.reqmts]/13.1.

  • Related