From f05402c04e596573c7d43835ee0239b02c97ac85 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 26 Mar 2026 19:08:54 +0100 Subject: [PATCH] Library: a stricter criterion for Lumiera iterators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On occasion of the recent improvements, I noticed that somewhere in the past I had misunderstood the meaning of the typedefs in iterators: * `reference` is the central definition; this is what the iterator yields * `value_type` is secondary; this is the type you use to store results So at times I defined only a `value_type`, wrongly assuming this to be the primary definition, and all the other ones to be ephemeral. Consequently the trait to detect a »Lumiera Forward Iterator« should be sharpened... ...which unveils a long-standing bug in our ''Duck Detector'' (it is not possible to define a pointer to a reference, causing a check for the `reference` typedef erroneously to fail. --- src/lib/iter-adapter-stl.hpp | 17 ++++++++++++----- src/lib/meta/duck-detector.hpp | 16 +++++++++------- src/lib/meta/trait.hpp | 7 ++++++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/lib/iter-adapter-stl.hpp b/src/lib/iter-adapter-stl.hpp index 96f68cf7c..d0c3b2aca 100644 --- a/src/lib/iter-adapter-stl.hpp +++ b/src/lib/iter-adapter-stl.hpp @@ -90,15 +90,18 @@ namespace iter_stl { /** - * helper baseclass to simplify - * defining customised wrapped STL iterators + * @internal helper baseclass to simplify defining customised wrapped STL iterators. + * @remark this is meant to be compliant to a STL input-iterator; + * it's _not_ a »Lumiera Forward Iterator« (lacks the bool check for iteration end) + * @warning minimal definition, since it is only intended to be wrapped into lib::RangeIter */ template struct WrappedStlIter : DEF { - using Iter = DEF::Iter; - using reference = DEF::reference; - using pointer = DEF::pointer; + using Iter = DEF::Iter; + using value_type = DEF::value_type; + using reference = DEF::reference; + using pointer = DEF::pointer; WrappedStlIter() : i_() { } @@ -112,6 +115,10 @@ namespace iter_stl { friend bool operator== (WrappedStlIter const& i1, WrappedStlIter const& i2) { return i1.i_ == i2.i_; } friend bool operator!= (WrappedStlIter const& i1, WrappedStlIter const& i2) { return i1.i_ != i2.i_; } + /** @note the following dummy definitions are required to fulfil the concept std::input_iterator */ + WrappedStlIter& operator++(int) { NOTREACHED("never used as STL iterator"); return *this; } + using difference_type = ptrdiff_t; + private: mutable Iter i_; }; diff --git a/src/lib/meta/duck-detector.hpp b/src/lib/meta/duck-detector.hpp index 301279d4c..6f04e0bbe 100644 --- a/src/lib/meta/duck-detector.hpp +++ b/src/lib/meta/duck-detector.hpp @@ -108,13 +108,15 @@ * and check the static bool value field. * @warning none of these checks can detect private members */ -#define META_DETECT_NESTED(_TYPE_) \ - template \ - class HasNested_##_TYPE_ \ - { \ - \ - template \ - static Yes_t check(X::_TYPE_ *); \ +#define META_DETECT_NESTED(_TYPE_) \ + template \ + class HasNested_##_TYPE_ \ + { \ + \ + template \ + > \ + static Yes_t check(int); \ template \ static No_t check(...); \ \ diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index 239cdfd60..9f157d3f0 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -493,19 +493,24 @@ namespace meta { * This is just a heuristic, based on some common properties * of such iterators; it is enough to distinguish it from an * STL container, but can certainly be refined. + * @note deliberately a Lumiera iterator does _not fulfil_ + * the concept std::input_iterator. And vice versa: + * a STL iterator lacks the `bool` check for iteration end. */ template class can_IterForEach { - using Type = Strip::Type; + using Type = Strip::TypeReferred; META_DETECT_NESTED(value_type); + META_DETECT_NESTED(reference); META_DETECT_OPERATOR_DEREF(); META_DETECT_OPERATOR_INC(); public: enum{ value = std::is_constructible::value and HasNested_value_type::value + and HasNested_reference::value and HasOperator_deref::value and HasOperator_inc::value };