TL;DR: In this case, the iterator type of the result of std::views::take is std::counted_iterator, which sometimes fails to model an iterator concept when it’s not expected to fail. This is LWG 3408 and is resolved by P2259.
This involves some really complicated mechanism.
Let
Tbe the iterator type ofvalues | std::views::filter(even) | std::views::transform(square),Rbestd::reverse_iterator<T>.
In the initializer of result3:
- The iterator type of
... | take(4)isstd::counted_iterator<R>. - The
iterator_traitsforstd::counted_iterator<R>matches the partial specializationstd::iterator_traits<std::counted_iterator<I>>. - Said partial specialization derives from
std::iterator_traits<I>. std::iterator_traits<R>is generated from the primary template: it provides a member namediterator_category, but not a member namediterator_concept.- The
iterator_categoryofRis the same as that ofT. - The
iterator_categoryofTisinput_iterator_tag, because its dereference operator does not return a reference, which is not allowed by C++17 ForwardIterator requirements. (Theiterator_conceptofTisbidirectional_iterator_tag.)
So in the end, std::iterator_traits<std::counted_iterator<R>> does not provide iterator_concept, and its iterator_category is input_iterator_tag.
Therefore, the result of ... | take(4) fails to model bidirectional_range, and thus it is rejected by views::reverse.
(The iterator type of ... | take(4) is not a counted_iterator when filter is removed from the pipeline; the iterator_category is not input_iterator_tag when transform is removed from the pipeline. So result1 and result2 do not trigger this error.)
This is essentially LWG 3408.