Library: introduce a concept for the »Lumiera Forward Iterator«

Well, finally.

Lumiera Iterators were conceived as a concept from the very beginning,
and this idea dates back even before C++11. Furthermore, over time some
''trait templates'' have been developed, to detect if some template argument
might match the known pattern of functions associated with a Lumiera Iterator.

Meanwhile this concept is used pervasively in the whole code base, and also
the traits templates proved to be reliable. It therefore seems that the time is ripe
to gradually introduce a genuine **concept** `lum_iter`

I'll take a defensive approach here, since any mistake would lead to
a massive breakage of compilation. The new concept is defined simply
by delegating to to the tried-and-tested trait template, which is
also renamed `can_IterForEach` ⟼ `can_LumieraIter`

One immediate benefit is that the compiler is now able to select
overloads based on that concept, which allows to drop the tricky
selection of variants based on the SFINAE technique and `enable_if`.

For validation, one very heavily used case of that pattern was switched
in `lib/format-util.hpp', which notably lies in the code-path used by `util::join`
This commit is contained in:
Fischlurch 2026-05-13 23:44:48 +02:00
parent d94bfe64b5
commit 3a491855e7
15 changed files with 76 additions and 242 deletions

View file

@ -100,7 +100,7 @@ namespace diff{
using std::__and_; using std::__and_;
using std::__not_; using std::__not_;
using lib::meta::enable_if; using lib::meta::enable_if;
using lib::meta::can_IterForEach; using lib::meta::can_LumieraIter;
using lib::meta::can_STL_ForEach; using lib::meta::can_STL_ForEach;
using DiffStep = TreeDiffLanguage::DiffStep; using DiffStep = TreeDiffLanguage::DiffStep;
@ -168,7 +168,7 @@ namespace diff{
* @note source iterator is copied into a heap allocated IterSource * @note source iterator is copied into a heap allocated IterSource
*/ */
template<class IT> template<class IT>
MutationMessage(IT&& ii, enable_if< can_IterForEach<IT>, void*> =nullptr) MutationMessage(IT&& ii, enable_if< can_LumieraIter<IT>, void*> =nullptr)
: _FrontEnd{iter_source::wrapIter (std::forward<IT>(ii))} : _FrontEnd{iter_source::wrapIter (std::forward<IT>(ii))}
{ } { }
@ -179,7 +179,7 @@ namespace diff{
*/ */
template<class CON> template<class CON>
MutationMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON> MutationMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON>
,__not_<can_IterForEach<CON>>>, void*> =nullptr) ,__not_<can_LumieraIter<CON>>>, void*> =nullptr)
: _FrontEnd{iter_source::eachEntry(container)} : _FrontEnd{iter_source::eachEntry(container)}
{ } { }

View file

@ -46,7 +46,7 @@
namespace util { namespace util {
using lib::meta::can_IterForEach; using lib::meta::lum_iter;
using std::string; using std::string;
using std::forward; using std::forward;
using std::move; using std::move;
@ -141,7 +141,7 @@ namespace util {
namespace { // helper to build range iterator on demand namespace { // helper to build range iterator on demand
template<class CON, typename TOGGLE = void> template<class CON>
struct _RangeIter struct _RangeIter
{ {
using StlIter = CON::const_iterator; using StlIter = CON::const_iterator;
@ -153,8 +153,8 @@ namespace util {
{ } { }
}; };
template<class IT> template<lum_iter IT>
struct _RangeIter<IT, lib::meta::enable_if< can_IterForEach<IT>> > struct _RangeIter<IT>
{ {
IT iter; IT iter;

View file

@ -431,11 +431,14 @@ namespace iter_stl {
/** create empty snapshot */ /** create empty snapshot */
IterSnapshot() { } IterSnapshot() { }
// standard copy operations acceptable
/** take snapshot by discharging the given Lumiera Forward iterator /** take snapshot by discharging the given Lumiera Forward iterator
* @warning depending on the implementation backing the source iterator, * @warning depending on the implementation backing the source iterator,
* this might or might not yield side-effects. * this might or might not yield side-effects.
*/ */
template<class IT> template<class IT, typename =meta::disable_if_self<IterSnapshot, IT>>
IterSnapshot (IT&& src) IterSnapshot (IT&& src)
{ {
for ( ; src; ++src) for ( ; src; ++src)
@ -446,7 +449,7 @@ namespace iter_stl {
* @warning depending on the implementation backing the source iterator, * @warning depending on the implementation backing the source iterator,
* this might or might not yield side-effects. * this might or might not yield side-effects.
*/ */
template<class IT> template<class IT, typename =meta::disable_if_self<IterSnapshot, IT>>
IterSnapshot (IT const& src) IterSnapshot (IT const& src)
{ {
for (IT copy{src}; copy; ++copy) for (IT copy{src}; copy; ++copy)
@ -469,11 +472,6 @@ namespace iter_stl {
buffer_.emplace_back (*pos); buffer_.emplace_back (*pos);
} }
IterSnapshot(IterSnapshot &&) = default;
IterSnapshot(IterSnapshot const&) = default;
IterSnapshot& operator= (IterSnapshot const&) = default;
IterSnapshot& operator= (IterSnapshot &&) = default;
explicit explicit
operator bool() const operator bool() const
{ {

View file

@ -193,7 +193,7 @@ namespace lib {
namespace iter { namespace iter {
using meta::is_StateCore; using meta::is_StateCore;
using meta::can_IterForEach; using meta::can_LumieraIter;
using meta::can_STL_ForEach; using meta::can_STL_ForEach;
using meta::ValueTypeBinding; using meta::ValueTypeBinding;
using meta::RefTraits; using meta::RefTraits;
@ -223,7 +223,7 @@ namespace lib {
template<class IT> template<class IT>
struct Trait struct Trait
{ {
static constexpr bool is_LumieraIter = can_IterForEach<IT>::value; static constexpr bool is_LumieraIter = meta::is_LumieraIter_v<IT>;
static constexpr bool is_STLIter = std::input_iterator<IT>; static constexpr bool is_STLIter = std::input_iterator<IT>;
static constexpr bool is_Legacy = legacy_traits_marked<IT>; static constexpr bool is_Legacy = legacy_traits_marked<IT>;
@ -579,7 +579,7 @@ namespace lib {
class IterStateCore class IterStateCore
: public IT : public IT
{ {
static_assert (iter::can_IterForEach<IT>::value static_assert (iter::can_LumieraIter<IT>::value
,"Lumiera Iterator required as source"); ,"Lumiera Iterator required as source");
protected: protected:
IT& IT&

View file

@ -250,7 +250,7 @@ namespace lib {
using std::is_lvalue_reference; using std::is_lvalue_reference;
using std::remove_reference_t; using std::remove_reference_t;
using meta::is_StateCore; using meta::is_StateCore;
using meta::can_IterForEach; using meta::can_LumieraIter;
using meta::can_STL_ForEach; using meta::can_STL_ForEach;
using meta::ValueTypeBinding; using meta::ValueTypeBinding;
using meta::has_TypeResult; using meta::has_TypeResult;
@ -259,20 +259,20 @@ namespace lib {
template<class SRC> template<class SRC>
struct shall_wrap_STL_Iter struct shall_wrap_STL_Iter
: __and_<can_STL_ForEach<SRC> : __and_<can_STL_ForEach<SRC>
,__not_<can_IterForEach<SRC>> ,__not_<can_LumieraIter<SRC>>
> >
{ }; { };
template<class SRC> template<class SRC>
struct shall_use_Lumiera_Iter struct shall_use_Lumiera_Iter
: __and_<can_IterForEach<SRC> : __and_<can_LumieraIter<SRC>
,__not_<is_StateCore<SRC>> ,__not_<is_StateCore<SRC>>
> >
{ }; { };
template<class SRC> template<class SRC>
struct shall_use_StateCore struct shall_use_StateCore
: __and_<__not_<can_IterForEach<SRC>> : __and_<__not_<can_LumieraIter<SRC>>
,is_StateCore<SRC> ,is_StateCore<SRC>
> >
{ }; { };
@ -361,12 +361,12 @@ namespace lib {
}; };
template<class SRC, typename RES> template<class SRC, typename RES>
struct _FlatteningTraits<SRC,RES, enable_if<__and_< is_lvalue_reference<RES>, can_IterForEach<RES> >>> struct _FlatteningTraits<SRC,RES, enable_if<__and_< is_lvalue_reference<RES>, can_LumieraIter<RES> >>>
{ {
using SrcAdapter = meta::RefTraits<SRC>::value_type; using SrcAdapter = meta::RefTraits<SRC>::value_type;
}; };
template<class SRC, typename RES> template<class SRC, typename RES>
struct _FlatteningTraits<SRC,RES, enable_if<__and_<__not_<is_lvalue_reference<RES>>, can_IterForEach<RES> >>> struct _FlatteningTraits<SRC,RES, enable_if<__and_<__not_<is_lvalue_reference<RES>>, can_LumieraIter<RES> >>>
{ {
using NestedIter = meta::RefTraits<RES>::value_type; using NestedIter = meta::RefTraits<RES>::value_type;
using SrcAdapter = iter_explorer::WrapperAdapter<SRC,NestedIter>; using SrcAdapter = iter_explorer::WrapperAdapter<SRC,NestedIter>;
@ -612,7 +612,7 @@ namespace lib {
class RedressAdapter class RedressAdapter
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source."); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source.");
using SrcRes = iter::Yield<SRC>; using SrcRes = iter::Yield<SRC>;
static_assert(meta::isLRef_v<SrcRes>, "Source iterator must yield its result by-ref."); static_assert(meta::isLRef_v<SrcRes>, "Source iterator must yield its result by-ref.");
@ -678,7 +678,7 @@ namespace lib {
class Expander class Expander
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
using _Trait = _ExpanderTraits<SRC,RES>; using _Trait = _ExpanderTraits<SRC,RES>;
using ResIter = _Trait::ResIter; using ResIter = _Trait::ResIter;
@ -897,10 +897,10 @@ namespace lib {
class Flattener class Flattener
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
using NestedIT = iter::Yield<SRC>; using NestedIT = iter::Yield<SRC>;
static_assert(can_IterForEach<NestedIT>::value, "flatten() operation expects nested iterator"); static_assert(can_LumieraIter<NestedIT>::value, "flatten() operation expects nested iterator");
public: public:
using value_type = meta::ValueTypeBinding<NestedIT>::value_type; using value_type = meta::ValueTypeBinding<NestedIT>::value_type;
@ -986,7 +986,7 @@ namespace lib {
class Transformer class Transformer
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
using TransformFunctor = function<RES(SRC&)>; using TransformFunctor = function<RES(SRC&)>;
using TransformedItem = wrapper::ItemWrapper<RES>; using TransformedItem = wrapper::ItemWrapper<RES>;
@ -1216,7 +1216,7 @@ namespace lib {
class Grouping class Grouping
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
protected: protected:
using Group = std::array<RES, grp>; using Group = std::array<RES, grp>;
@ -1350,7 +1350,7 @@ namespace lib {
class GroupAggregator class GroupAggregator
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
protected: protected:
using SrcValue = meta::ValueTypeBinding<SRC>::value_type; using SrcValue = meta::ValueTypeBinding<SRC>::value_type;
@ -1439,7 +1439,7 @@ namespace lib {
class Filter class Filter
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
protected: protected:
using FilterPredicate = function<bool(SRC&)>; using FilterPredicate = function<bool(SRC&)>;
@ -1540,7 +1540,7 @@ namespace lib {
: public Filter<SRC> : public Filter<SRC>
{ {
using _Filter = Filter<SRC>; using _Filter = Filter<SRC>;
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
public: public:
MutableFilter() =default; MutableFilter() =default;
@ -1705,7 +1705,7 @@ namespace lib {
class StopTrigger class StopTrigger
: public IterStateCore<SRC> : public IterStateCore<SRC>
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
using Core = IterStateCore<SRC>; using Core = IterStateCore<SRC>;
using Cond = function<bool(SRC&)>; using Cond = function<bool(SRC&)>;
@ -1905,7 +1905,7 @@ namespace lib {
class IterExplorer class IterExplorer
: public SRC : public SRC
{ {
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source"); static_assert(can_LumieraIter<SRC>::value, "Lumiera Iterator required as source");
public: public:

View file

@ -405,7 +405,7 @@ namespace lib {
class ValueAdapter class ValueAdapter
: public SRC : public SRC
{ {
static_assert (can_IterForEach<SRC>::value, "Lumiera Iterator required as source."); static_assert (can_LumieraIter<SRC>::value, "Lumiera Iterator required as source.");
public: public:
SRC::value_type SRC::value_type

View file

@ -506,7 +506,7 @@ namespace meta {
* @see IterableClassification_test * @see IterableClassification_test
*/ */
template<typename T> template<typename T>
class can_IterForEach class can_LumieraIter
{ {
using Type = Strip<T>::TypeReferred; using Type = Strip<T>::TypeReferred;
@ -524,6 +524,12 @@ namespace meta {
}; };
}; };
template<class IT>
constexpr bool is_LumieraIter_v = meta::can_LumieraIter<IT>::value;
template<class IT>
concept lum_iter = is_LumieraIter_v<IT>;
/** Trait template to detect a type exposing a »state core« API. /** Trait template to detect a type exposing a »state core« API.
@ -531,10 +537,10 @@ namespace meta {
* with the help of lib::IterStateWrapper or lib::IterableDecorator. * with the help of lib::IterStateWrapper or lib::IterableDecorator.
* This check is heuristic, based on the presence of function names. * This check is heuristic, based on the presence of function names.
*/ */
template<typename T> template<typename COR>
class is_StateCore class is_StateCore
{ {
using Type = Strip<T>::TypeReferred; using Type = Strip<COR>::TypeReferred;
META_DETECT_FUNCTION_ARGLESS(checkPoint); META_DETECT_FUNCTION_ARGLESS(checkPoint);
META_DETECT_FUNCTION_ARGLESS(iterNext); META_DETECT_FUNCTION_ARGLESS(iterNext);
@ -547,10 +553,19 @@ namespace meta {
}; };
}; };
template<class COR>
constexpr bool is_StateCore_v = is_StateCore<COR>::value;
template<class COR>
concept state_core = is_StateCore_v<COR>;
/** Trait template to detect a type usable with the STL for-each loop. /** Trait template to detect a type usable with the STL for-each loop.
* Basically we're looking for the functions to get the begin/end iterator * Basically we're looking for the functions to get the begin/end iterator
* @remark many Lumiera Iterators define those additional functions any
* can thus be used in a for-each loop, since a default-constructed
* Lumiera Iterator can act as an "end" sentinel.
*/ */
template<typename T> template<typename T>
class can_STL_ForEach class can_STL_ForEach

View file

@ -1,181 +0,0 @@
/*
TUPLE-ACCESSOR.hpp - metaprogramming utilities for type and data tuples
Copyright (C)
2016 Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
*/
/** @file tuple-accessor.hpp
** Helper templates to access parts of a tuple.
**
** @todo 2026 this is old metaprogramming code, largely obsoleted by newer features of the C++ language.
** However, since this code is still used in some basic support facilities, it was separated out,
** so that it can be refactored as time permits.
**
** @see TupleHelper_test
**
*/
#ifndef LIB_META_TUPLE_ACCESSOR_H
#define LIB_META_TUPLE_ACCESSOR_H
#include "lib/meta/tuple-helper.hpp"
#include "lib/format-obj.hpp"
#include <string>
namespace lib {
namespace meta {
/**
* Decorating a tuple type with auxiliary data access operations.
* This helper template builds up a subclass of the given TUP (base) type
* (which is assumed to be a Tuple or at least need to be copy constructible
* from `Tuple<TYPES>` ). The purpose is to use the Tuple as storage record, but
* to add a layer of access functions, which in turn might rely on the exact
* type of the individual elements within the Tuple. To achieve this, for each
* type within the Tuple, the TUP type is decorated with an instance of the
* template passed in as template template parameter _X_. Each of these
* decorating instances is provided with an index number, allowing to
* access "his" specific element within the underlying tuple.
*
* The decorating template _X_ need to take its own base class as template
* parameter. Typically, operations on _X_ will be defined in a recursive fashion,
* calling down into this templated base class. To support this, an instantiation
* of _X_ with the empty type sequence is generated for detecting recursion end
* (built as innermost decorator, i.e. the immediate subclass of TUP)
*/
template
< template<class,class,class, uint> class _X_ ///< user provided template<Type, Base, TupleType, arg-idx>
, typename TYPES ///< Sequence of types to use within the Accessor
, class TUP =Tuple<TYPES> ///< the tuple type to build on
, uint i = 0 ///< tuple element index counter
>
class BuildTupleAccessor
{
// prepare recursion...
using Head = Split<TYPES>::Head;
using Tail = Split<TYPES>::Tail;
using NextBuilder = BuildTupleAccessor<_X_, Tail,TUP, i+1>;
using NextAccessor = NextBuilder::Product;
public:
/** type of the product created by this template.
* Will be a subclass of TUP */
using Product = _X_< Head // the type to use for this accessor
, NextAccessor // the base type to inherit from
, TUP // the tuple type we build upon
, i // current element index
>;
};
template
< template<class,class,class, uint> class _X_
, class TUP
, uint i
>
class BuildTupleAccessor< _X_, Types<>, TUP, i>
{
public:
using Product = _X_<Nil, TUP, TUP, i>; // Note: i == tuple size
};
/**
* Helper to dump tuple contents.
* Defined to act as "Accessor" for BuildTupleAccessor, this helper template
* allows to create a recursive operation to invoke string conversion on
* all elements within any given tuple.
*/
template
< typename TY
, class BASE
, class TUP
, uint idx
>
struct TupleElementDisplayer
: BASE
{
using BASE::BASE;
std::string
dump (std::string const& prefix ="(") const
{
return BASE::dump (prefix + util::toString(std::get<idx>(*this))+",");
}
};
template<class TUP, uint n>
struct TupleElementDisplayer<Nil, TUP, TUP, n>
: TUP
{
TupleElementDisplayer (TUP const& tup)
: TUP(tup)
{ }
std::string
dump (std::string const& prefix ="(") const
{
if (1 < prefix.length())
// remove the trailing comma
return prefix.substr (0, prefix.length()-1) +")";
else
return prefix+")";
}
};
/**
* convenience function to dump a given tuple's contents.
* Using the BuildTupleAccessor, we layer a stack of Instantiations of
* the TupleElementDisplayer temporarily on top of the given tuple,
* just to invoke a recursive call chain through these layers
* and get a string representation of each element in the
* tuple.
*/
template<typename...TYPES>
inline std::string
dump (std::tuple<TYPES...> const& tuple)
{
using BuildAccessor = BuildTupleAccessor<TupleElementDisplayer, Types<TYPES...>>;
using Displayer = BuildAccessor::Product ;
return static_cast<Displayer const&> (tuple)
.dump();
}
}} // namespace lib::meta
// add a specialisation to enable tuple string conversion
namespace util {
template<typename...TYPES>
struct StringConv<std::tuple<TYPES...>>
{
static std::string
invoke (std::tuple<TYPES...> const& tuple) noexcept
try {
return "«"+typeStr(tuple)
+ "»──" + lib::meta::dump (tuple);
}
catch(...) { return FAILURE_INDICATOR; }
};
} // namespace util
#endif /*LIB_META_TUPLE_ACCESSOR_H*/

View file

@ -70,6 +70,7 @@
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <sstream>
#include <functional> #include <functional>

View file

@ -57,14 +57,14 @@ namespace util {
typedef lib::meta::Unwrap<T>::Type TaT; typedef lib::meta::Unwrap<T>::Type TaT;
enum{ value = lib::meta::can_STL_ForEach<TaT>::value enum{ value = lib::meta::can_STL_ForEach<TaT>::value
&&!lib::meta::can_IterForEach<T>::value &&!lib::meta::can_LumieraIter<T>::value
}; };
}; };
template<typename T> template<typename T>
struct treat_as_LumieraIterator struct treat_as_LumieraIterator
{ {
enum{ value = lib::meta::can_IterForEach<T>::value enum{ value = lib::meta::can_LumieraIter<T>::value
}; };
}; };

View file

@ -56,7 +56,7 @@ namespace util {
using lib::meta::disable_if; using lib::meta::disable_if;
using lib::meta::can_STL_ForEach; using lib::meta::can_STL_ForEach;
using lib::meta::can_IterForEach; using lib::meta::can_LumieraIter;
@ -108,7 +108,7 @@ namespace util {
template <typename Container template <typename Container
,typename FUN ,typename FUN
> >
inline disable_if< can_IterForEach<Container>, inline disable_if< can_LumieraIter<Container>,
FUN > FUN >
for_each (Container const& coll, FUN doIt) for_each (Container const& coll, FUN doIt)
{ {
@ -124,7 +124,7 @@ namespace util {
template <typename IT template <typename IT
,typename FUN ,typename FUN
> >
inline enable_if< can_IterForEach<IT>, inline enable_if< can_LumieraIter<IT>,
FUN > FUN >
for_each (IT const& ii, FUN doIt) for_each (IT const& ii, FUN doIt)
{ {
@ -152,7 +152,7 @@ namespace util {
template <typename IT template <typename IT
,typename FUN ,typename FUN
> >
inline enable_if< can_IterForEach<IT>, inline enable_if< can_LumieraIter<IT>,
bool > bool >
and_all (IT const& ii, FUN predicate) and_all (IT const& ii, FUN predicate)
{ {
@ -179,7 +179,7 @@ namespace util {
template <typename IT template <typename IT
,typename FUN ,typename FUN
> >
inline enable_if< can_IterForEach<IT>, inline enable_if< can_LumieraIter<IT>,
bool > bool >
has_any (IT const& ii, FUN predicate) has_any (IT const& ii, FUN predicate)
{ {

View file

@ -20,6 +20,7 @@
#include "test/run.hpp" #include "test/run.hpp"
#include "lib/iter-zip.hpp" #include "lib/iter-zip.hpp"
#include "lib/iter-explorer.hpp" #include "lib/iter-explorer.hpp"
#include "lib/meta/tuple-helper.hpp"
#include "test/test-helper.hpp" #include "test/test-helper.hpp"
#include "lib/format-util.hpp" #include "lib/format-util.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"

View file

@ -131,20 +131,20 @@ namespace test {
CHECK (false == can_STL_ForEach<LumieraCoreIter>::value ); CHECK (false == can_STL_ForEach<LumieraCoreIter>::value );
// detect Lumiera Forward Iterator // detect Lumiera Forward Iterator
CHECK (false == can_IterForEach<TimeVector>::value ); CHECK (false == can_LumieraIter<TimeVector>::value );
CHECK (false == can_IterForEach<LongSet> ::value ); CHECK (false == can_LumieraIter<LongSet> ::value );
CHECK (false == can_IterForEach<CharMap> ::value ); CHECK (false == can_LumieraIter<CharMap> ::value );
CHECK (false == can_IterForEach<BoolList> ::value ); CHECK (false == can_LumieraIter<BoolList> ::value );
CHECK (false == can_IterForEach<ShortDeque>::value ); CHECK (false == can_LumieraIter<ShortDeque>::value );
CHECK (false == can_IterForEach<CustomCont>::value ); CHECK (false == can_LumieraIter<CustomCont>::value );
CHECK ( true == can_IterForEach<LumieraRangeIter> ::value ); CHECK ( true == can_LumieraIter<LumieraRangeIter> ::value );
CHECK ( true == can_IterForEach<LumieraFilteredIter> ::value ); CHECK ( true == can_LumieraIter<LumieraFilteredIter> ::value );
CHECK ( true == can_IterForEach<LumieraTransformedIter>::value ); CHECK ( true == can_LumieraIter<LumieraTransformedIter>::value );
CHECK ( true == can_IterForEach<CustomLumieraIter> ::value ); CHECK ( true == can_LumieraIter<CustomLumieraIter> ::value );
CHECK (false == can_IterForEach<CustomStateCore>::value ); CHECK (false == can_LumieraIter<CustomStateCore>::value );
CHECK ( true == can_IterForEach<LumieraCoreIter>::value ); // Note: Lumiera iterator capability added as wrapper CHECK ( true == can_LumieraIter<LumieraCoreIter>::value ); // Note: Lumiera iterator capability added as wrapper
// detect State Core // detect State Core
CHECK (false == is_StateCore<TimeVector>::value ); CHECK (false == is_StateCore<TimeVector>::value );

View file

@ -283,7 +283,7 @@ namespace test{
CHECK (horror.isParseFail()); CHECK (horror.isParseFail());
// CsvParser is a »Lumiera Forward Iterator« // CsvParser is a »Lumiera Forward Iterator«
CHECK (meta::can_IterForEach<CsvParser>::value); CHECK (meta::lum_iter<CsvParser>);
} }

View file

@ -33,7 +33,7 @@ using util::first;
using util::last; using util::last;
using lib::meta::can_STL_ForEach; using lib::meta::can_STL_ForEach;
using lib::meta::can_IterForEach; using lib::meta::can_LumieraIter;
using lib::meta::can_STL_backIteration; using lib::meta::can_STL_backIteration;
using boost::lexical_cast; using boost::lexical_cast;
@ -131,8 +131,8 @@ namespace test {
CHECK (!can_STL_ForEach<RangeI>::value); CHECK (!can_STL_ForEach<RangeI>::value);
CHECK (!can_STL_backIteration<RangeI>::value); CHECK (!can_STL_backIteration<RangeI>::value);
CHECK (!can_IterForEach<VecI>::value); CHECK (!can_LumieraIter<VecI>::value);
CHECK ( can_IterForEach<RangeI>::value); CHECK ( can_LumieraIter<RangeI>::value);
} }
}; };