Skip to content

Commit 130fc5f

Browse files
committed
Address iterator_category failing to compile for input iterators
The wording of P2727R4 states, with respect to the iterator_category type alias: "The nested type iterator_category is defined if and only if IteratorConcept is derived from forward_iterator_tag." Previously, this implementation had attempted to implement this using a class template detail::iter_cat, which had a specialization that contained an iterator_category member type alias which was only enabled if IteratorConcept was derived from std::forward_iterator_tag. However, the iter_category member type alias of iterator_interface itself was specified as detail::iter_cat</* ... */>>::iterator_category, which caused iterator_interface to simply fail to compile if IteratorConcept was not derived from forward_iterator_tag as detail::iter_cat's iterator_category was not found. This commit addresses the issue by removing the iterator_category member type alias from iterator_interface itself and making iterator_interface provide the member type alias by inheriting from detail::iter_cat, which satisfies the requirement in the wording. It also adds a reproducing unit test.
1 parent fed466b commit 130fc5f

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

include/beman/iterator_interface/iterator_interface.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ struct iter_cat<IteratorConcept, ReferenceType, false> {};
142142

143143
template <typename IteratorConcept, typename ReferenceType>
144144
struct iter_cat<IteratorConcept, ReferenceType, true> {
145+
private:
145146
static constexpr auto compute_category_tag() {
146147
if constexpr (!std::is_reference_v<ReferenceType>) {
147148
return std::input_iterator_tag{};
@@ -154,19 +155,18 @@ struct iter_cat<IteratorConcept, ReferenceType, true> {
154155
}
155156
}
156157

157-
using TagType = std::invoke_result_t<decltype(compute_category_tag)>;
158-
using iterator_category = TagType;
158+
public:
159+
using iterator_category = std::invoke_result_t<decltype(compute_category_tag)>;
159160
};
160161

161162
} // namespace detail
162163

163164
template <class IteratorConcept, class ValueType, class Reference, class Pointer, class DifferenceType>
164-
class iterator_interface {
165+
class iterator_interface
166+
: detail::iter_cat<IteratorConcept, Reference, std::derived_from<IteratorConcept, std::forward_iterator_tag>>
167+
{
165168
public:
166169
using iterator_concept = IteratorConcept;
167-
using iterator_category =
168-
detail::iter_cat<IteratorConcept, Reference, std::derived_from<IteratorConcept, std::forward_iterator_tag>>::
169-
iterator_category;
170170
using value_type = remove_const_t<ValueType>;
171171
using reference = Reference;
172172
using pointer = conditional_t<is_same_v<iterator_concept, output_iterator_tag>, void, Pointer>;

tests/beman/iterator_interface/iterator_interface.test.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <gtest/gtest.h>
88

99
#include <algorithm>
10+
#include <iterator>
1011
#include <ranges>
1112

1213
namespace beman {
@@ -119,5 +120,34 @@ TEST(IteratorTest, OperatorArrow) {
119120
ASSERT_EQ(ai->f(), 3);
120121
}
121122

123+
struct dummy_input_iterator :
124+
public ext_iterator_interface_compat<
125+
dummy_input_iterator, std::input_iterator_tag, int, int const&, void, std::ptrdiff_t> {
126+
constexpr dummy_input_iterator() { }
127+
dummy_input_iterator(dummy_input_iterator const&) = delete;
128+
dummy_input_iterator& operator=(dummy_input_iterator const&) = delete;
129+
dummy_input_iterator(dummy_input_iterator&&) = default;
130+
dummy_input_iterator& operator=(dummy_input_iterator&&) = default;
131+
constexpr reference operator*() const {
132+
return foo;
133+
}
134+
constexpr dummy_input_iterator& operator++() {
135+
return *this;
136+
}
137+
constexpr void operator++(int) {}
138+
139+
friend constexpr bool operator==(std::default_sentinel_t const&,
140+
dummy_input_iterator const&) {
141+
return true;
142+
}
143+
144+
friend beman::iterator_interface::iterator_interface_access;
145+
146+
int foo = 0;
147+
};
148+
149+
static_assert(std::input_iterator<dummy_input_iterator>);
150+
static_assert(!std::forward_iterator<dummy_input_iterator>);
151+
122152
} // namespace iterator_interface
123153
} // namespace beman

0 commit comments

Comments
 (0)