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

20
以下代码在nsize_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
}

https://godbolt.org/z/a3eGeMWqh


你所提供的示例对于long类型也无法正常工作。在我看来,这似乎是一个g++的bug。(在MSVC中可以正常工作。) - Adrian Mole
size_t和long long是我们应用程序中常用的类型,用于boost::irange / counting_iterator。如果iota_view不能以某种方式替代它们(尽管可能会丢弃有符号整数支持的差异类型),那将是遗憾的。 - undefined
2个回答

19
为了解决整数溢出问题,在libstdc++中,iota_view<uint64_t, uint64_t>::iterator的差异类型将会是__int128,它是一个整数类类型
具有整数类差异类型的迭代器不是C++17输入迭代器,因此这使得vector模板推断失败,因为迭代器对参数不符合__LegacyInputIterator的要求(即差异类型应该只是(有符号)整数类型)。
值得注意的是,在GNU扩展下,__int128被视为整数类型(它的模型是std::integral),在--std=gnu++20标志下,您的代码将是格式良好的。

13

我认为是否允许此扣除确实未指定。

您想在此使用的扣除指南要求迭代器是(传统的)输入迭代器。实现将验证这一点的程度大多是未指定的。它可能会或可能不会检查标准中列出的要求。有关详细信息,请参见[container.requirements.general]/18

然而,其中一个要求是difference_type是“带符号整数类型”(或void),请参见[iterator.iterators]/2.2

另一方面,iota_view的迭代器仅在存在比值类型宽度更大的宽度的带符号整数类型时才被指定为具有difference_type。对于size_t通常不是这种情况。在这种情况下,标准仅要求difference_type是“类似于带符号整数的类型”。有关详细信息,请参见[range.iota.view]/1[sequence.reqmts]/13.3

< p >一个类似于有符号整数的类型也可以是行为类似于整数的非整数类型。但如果选择的类型实际上不是整数类型,则迭代器不满足传统的迭代器要求,因此无法满足推导指南的要求。< /p > < p >您可以检查< code >std::begin(view)::difference_type< /code >,以查看GCC选择了< code >__int128< /code >,它的行为类似于整数,但实现并不认为它是扩展整数类型(< code >std::is_integral_v<__int128>< /code >为< code >false< /code >)。< /p > < p >GCC仍然将迭代器的< code >iterator_category< /code >成员设置为< code >std::input_iterator_tag< /code >,但根据LWG 3670的解决方案,在这种情况下应该删除它,而且我认为这个解决方案也表明< code >std::iota_view< /code >的迭代器在这种情况下确实不能保证是传统的迭代器。我不太确定这里是否存在缺陷。如果这是故意的,那么对我来说似乎很不幸。< /p > < p >构造函数本身也是如此,因此在< code >std::vector< /code >上指定模板参数也无法解决这个问题。请参见[sequence.reqmts]/13.1。< /p >

1
显然,当使用 --std=gnu++2b 时,std::is_integral_v<__int128>true,并且该代码会编译。 - Chris_F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接