为什么 std::vector 不能接受 size_t 类型的 iota_view 迭代器?

Chr*_*s_F 20 c++ iterator c++20 std-ranges

以下代码在nis时无法编译,但在和size_t时运行良好。intunsigned

#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 iterators
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/a3eGeMWqh

康桓瑋*_*康桓瑋 19

为了解决整数溢出的问题, libstdc++中iota_view<uint64_t, uint64_t>::iterator会出现差异类型,它是一个整型类类型__int128

具有整数类差异类型的迭代器不是 C++17 输入迭代器,因此这会导致vector模板推导失败,因为迭代器对参数不满足以下要求__LegacyInputIterator(即差异类型只能是(有符号)整型) 。

值得注意的是,在 GNU 扩展下__int128被视为整型(模型std::integral),您的代码将在该标志下格式良好--std=gnu++20


use*_*522 13

我想,是否允许这种扣除,确实没有明确规定。

您要在此处使用的推导指南要求迭代器是(旧的)输入迭代器。(大部分)未指定实现将在何种程度上验证这一点。它可能会或可能不会检查标准中列出的要求。有关详细信息,请参阅[container.requirements.general]/18

然而,要求之一是difference_type有符号整数类型”(或void),请参阅[iterator.iterators]/2.2

另一方面,如果存在宽度大于值类型宽度的类型iota_view,则迭代器仅被指定为有符号整数类型。通常情况并非如此。在这种情况下,标准仅要求是“有符号整数类型”。有关详细信息,请参阅[range.iota.view]/1[sequence.reqmts]/13.3difference_typesize_tdifference_type

符号整数类型也可能是行为类似的非整数类型。但是,如果选择的类型实际上不是整数类型,则迭代器不满足遗留迭代器要求,因此无法满足推导指南的要求。

您可以检查std::begin(view)::difference_typeGCC 选择__int128,其行为类似于整数,但其实现不考虑扩展整数类型(std::is_integral_v<__int128>is false)。

GCC 仍然给予迭代器 astd::input_iterator_tag作为iterator_category成员,但是根据LWG 3670的决议,在这种情况下应该删除该决议,并且该决议似乎也向我表明, 的迭代器std::iota_view实际上不应该保证是遗留迭代器在这个情况下。我对此了解不够,无法确定这里是否存在缺陷。如果这是有意为之的话,我觉得很不幸。

这同样适用于构造函数本身,因此指定模板参数也std::vector不会解决此问题。请参阅[sequence.reqmts]/13.1