[英]Why does views::reverse not work with iota_view<int64_t, int64_t>
我有以下 C++ 程序,由于某种原因,我不能使用int64_t
作为模板参数。
#include <iostream>
#include <ranges>
template<typename T>
void fn() {
for (auto val : std::ranges::iota_view{T{1701}, T{8473}}
| std::views::reverse
| std::views::take(5))
{
std::cout << val << std::endl;
}
}
int main()
{
fn<int16_t>();
fn<int32_t>();
// does not compile:
// fn<int64_t>();
}
这是预期的(我做错了什么),还是只是编译器/标准库中的一些不幸的错误?
注意:当我删除std::views::reverse
代码也会为int64_t
编译。
这是一个 libstdc++ 错误,已提交100639 。
iota
是一个令人惊讶的复杂范围。 特别是,我们需要为要递增的类型选择足够宽的difference_type
类型以避免溢出(另请参见P1522 )。 结果,我们在[range.iota]中有:
让
IOTA-DIFF-T(W)
定义如下:
- [...]
- 否则,
IOTA-DIFF-T(W)
是一个带符号的 integer 类型,其宽度大于W
的宽度(如果存在这种类型)。- 否则,
IOTA-DIFF-T(W)
是未指定的带符号整数类型 ([iterator.concept.winc]),其宽度不小于W
的宽度。[注 1:未指定此类型是否满足
weakly_incrementable
。 ——尾注]
对于iota_view<int64_t, int64_t>
,我们的差异类型是__int128
(足够宽的有符号整数类型)。 在 gcc 上, signed_integral<__int128>
在以一致模式 ( -std=c++20
) 编译时为false
,在扩展 ( -std=gnu++20
) 下为true
。
现在,在 libstdc++ 中, reverse_view
实现为:
template<typename _Iterator>
class reverse_iterator
: public iterator<typename iterator_traits<_Iterator>::iterator_category,
typename iterator_traits<_Iterator>::value_type,
typename iterator_traits<_Iterator>::difference_type,
typename iterator_traits<_Iterator>::pointer,
typename iterator_traits<_Iterator>::reference>
{
// ...
typedef typename __traits_type::reference reference;
// ...
_GLIBCXX17_CONSTEXPR reference operator*() const;
// ...
};
这不是指定reverse_iterator
的方式。 [reverse.iterator]将reference
类型定义为:
using reference = iter_reference_t<Iterator>;
不同之处在于后者仅表示*it
的类型,而前者实际上通过iterator_traits
并尝试确定如果It::reference
作为类型不存在时reference
的含义。 该确定在[iterator.traits]中指定:
否则,如果
I
满足仅展示概念cpp17-input-iterator
,则iterator_traits<I>
具有以下可公开访问的成员:[...]
其中reference
是I::reference
如果它存在或iter_reference_t<I>
如果它不存在。 这看起来是一回事,但我们必须首先满足cpp17-input-iterator<I>
。 并且cpp17-input-iterator<I>
需要,除其他外:
template<class I>
concept cpp17-input-iterator =
cpp17-iterator<I> && equality_comparable<I> && requires(I i) {
// ...
requires signed_integral<typename incrementable_traits<I>::difference_type>;
};
所以基本上,当且仅当signed_integral<__int128>
成立时, iterator_t<iota_view<int64_t, int64_t>>
满足cpp17-input-iterator
,这仅在我们在-std=gnu++20
中编译时才成立。
但是我们不需要满足这个要求,因为reverse_iterator<I>
应该直接使用iter_reference_t<I>
而不是 go 通过iterator_traits
,这需要检查signed_integral<__int128>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.