Several iterator types for view adaptors have wording like this (from [range.filter.iterator]):
iterator::iterator_category is defined as follows:
Let C denote the type iterator_traits<iterator_t<V>>::iterator_category.
If C models derived_from<bidirectional_iterator_tag>, then iterator_category denotes bidirectional_iterator_tag.
Otherwise, if C models derived_from<forward_iterator_tag>, then iterator_category denotes forward_iterator_tag.
Otherwise, iterator_category denotes C.
We could avoid the repetition with an exposition-only helper along the lines of:
template<class C, class... Cats>
struct floor-cat
{ using type = C; };
template<class C, class Cat, class... Cats>
struct floor-cat
: conditional<derived_from<C, Cat>, Cat, floor-cat<C, Cats...>>
{ };
template<class T, class... Cats>
using floor-cat-t = typename floor-cat<T, Cats...>::type;
And then define iterator::iterator_category for the example above as floor-cat<iterator_traits<iterator_t<V>>::iterator_category, bidirectional_iterator_tag, forward_iterator_tag>.
Several iterator types for view adaptors have wording like this (from [range.filter.iterator]):
We could avoid the repetition with an exposition-only helper along the lines of:
And then define
iterator
::iterator_category
for the example above asfloor-cat
<iterator_traits<iterator_t<V>>::iterator_category, bidirectional_iterator_tag, forward_iterator_tag>
.