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.