Library: a stricter criterion for Lumiera iterators

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.
This commit is contained in:
Fischlurch 2026-03-26 19:08:54 +01:00
parent fbda9baeb3
commit f05402c04e
3 changed files with 27 additions and 13 deletions

View file

@ -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<typename DEF>
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_;
};

View file

@ -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<typename TY> \
class HasNested_##_TYPE_ \
{ \
\
template<class X> \
static Yes_t check(X::_TYPE_ *); \
#define META_DETECT_NESTED(_TYPE_) \
template<typename TY> \
class HasNested_##_TYPE_ \
{ \
\
template<class X \
,typename = std::void_t<typename X::_TYPE_> \
> \
static Yes_t check(int); \
template<class> \
static No_t check(...); \
\

View file

@ -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<typename T>
class can_IterForEach
{
using Type = Strip<T>::Type;
using Type = Strip<T>::TypeReferred;
META_DETECT_NESTED(value_type);
META_DETECT_NESTED(reference);
META_DETECT_OPERATOR_DEREF();
META_DETECT_OPERATOR_INC();
public:
enum{ value = std::is_constructible<bool, Type>::value
and HasNested_value_type<Type>::value
and HasNested_reference<Type>::value
and HasOperator_deref<Type>::value
and HasOperator_inc<Type>::value
};