这是一个 libstdc++ 错误,已提交100639。
iota
是一个令人惊讶的复杂范围。特别是,我们需要为difference_type
要递增的类型选择足够宽的 a 以避免溢出(另请参见P1522)。结果,我们在[range.iota]中有:
让我们IOTA-DIFF-T(W)
定义如下:
- [...]
- 否则,
IOTA-DIFF-T(W)
是一个有符号整数类型,其宽度大于W
如果存在这种类型的宽度。
- 否则,
IOTA-DIFF-T(W)
是宽度不小于W
.
[注 1:未指定此类型是否满足weakly_incrementable
. ——尾注]
对于iota_view<int64_t, int64_t>
,我们的差异类型是__int128
(一个足够宽的有符号整数类型)。在 gcc 上,signed_integral<__int128>
是false
在符合模式 ( -std=c++20
) 和true
扩展 ( -std=gnu++20
) 下编译时。
现在,在 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
并试图确定reference
ifIt::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>;
};
所以基本上,iterator_t<iota_view<int64_t, int64_t>>
满足cpp17-input-iterator
当且仅当signed_integral<__int128>
成立,这仅在我们编译时才成立-std=gnu++20
。
但是我们应该不需要满足这个要求,因为reverse_iterator<I>
应该直接使用iter_reference_t<I>
而不是通过iterator_traits
,必须检查哪些旁路signed_integral<__int128>
。