Это ошибка libstdc++, отправлено 100639.
iota
— удивительно сложный диапазон. В частности, нам нужно выбрать difference_type
, достаточно широкий для типа, который мы увеличиваем, чтобы избежать переполнения (см. также P1522 а>). В результате имеем в [range.iota]:
Пусть IOTA-DIFF-T(W)
определяется следующим образом:
- [...]
- В противном случае
IOTA-DIFF-T(W)
является целочисленным типом со знаком, ширина которого больше, чем ширина W
, если такой тип существует.
- В противном случае
IOTA-DIFF-T(W)
является неуказанным целым числом со знаком ([iterator.concept.winc]) шириной не менее ширины 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
, если It::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>
.
person
Barry
schedule
17.05.2021
int16_t
,int32_t
иint64_t
. - person eerorika   schedule 17.05.2021