From 130fc5f8479d3aec2772a0b851988b978acd8c66 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Wed, 13 Nov 2024 19:10:04 -0500 Subject: [PATCH] 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. --- .../iterator_interface/iterator_interface.hpp | 12 ++++---- .../iterator_interface.test.cpp | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/include/beman/iterator_interface/iterator_interface.hpp b/include/beman/iterator_interface/iterator_interface.hpp index e1445d9..4e4be1a 100644 --- a/include/beman/iterator_interface/iterator_interface.hpp +++ b/include/beman/iterator_interface/iterator_interface.hpp @@ -142,6 +142,7 @@ struct iter_cat {}; template struct iter_cat { +private: static constexpr auto compute_category_tag() { if constexpr (!std::is_reference_v) { return std::input_iterator_tag{}; @@ -154,19 +155,18 @@ struct iter_cat { } } - using TagType = std::invoke_result_t; - using iterator_category = TagType; +public: + using iterator_category = std::invoke_result_t; }; } // namespace detail template -class iterator_interface { +class iterator_interface + : detail::iter_cat> +{ public: using iterator_concept = IteratorConcept; - using iterator_category = - detail::iter_cat>:: - iterator_category; using value_type = remove_const_t; using reference = Reference; using pointer = conditional_t, void, Pointer>; diff --git a/tests/beman/iterator_interface/iterator_interface.test.cpp b/tests/beman/iterator_interface/iterator_interface.test.cpp index fb707a1..6cea90a 100644 --- a/tests/beman/iterator_interface/iterator_interface.test.cpp +++ b/tests/beman/iterator_interface/iterator_interface.test.cpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace beman { @@ -119,5 +120,34 @@ TEST(IteratorTest, OperatorArrow) { ASSERT_EQ(ai->f(), 3); } +struct dummy_input_iterator : + public ext_iterator_interface_compat< + dummy_input_iterator, std::input_iterator_tag, int, int const&, void, std::ptrdiff_t> { + constexpr dummy_input_iterator() { } + dummy_input_iterator(dummy_input_iterator const&) = delete; + dummy_input_iterator& operator=(dummy_input_iterator const&) = delete; + dummy_input_iterator(dummy_input_iterator&&) = default; + dummy_input_iterator& operator=(dummy_input_iterator&&) = default; + constexpr reference operator*() const { + return foo; + } + constexpr dummy_input_iterator& operator++() { + return *this; + } + constexpr void operator++(int) {} + + friend constexpr bool operator==(std::default_sentinel_t const&, + dummy_input_iterator const&) { + return true; + } + + friend beman::iterator_interface::iterator_interface_access; + + int foo = 0; +}; + +static_assert(std::input_iterator); +static_assert(!std::forward_iterator); + } // namespace iterator_interface } // namespace beman