diff --git a/research/try.cpp b/research/try.cpp index 1a3dbefc4..b6a9a7da6 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -82,9 +82,14 @@ using lib::diff::GenNode; using lib::P; using lib::meta::enable_if; using lib::meta::typeStr; +using lib::meta::is_basically; +using lib::meta::can_lexical2string; using lib::meta::can_convertToString; using lib::meta::CustomStringConv; +using lib::meta::Strip; +using std::__and_; +using std::__not_; using std::string; using std::cout; using std::endl; @@ -108,50 +113,6 @@ stringz (P ptr) -/////////////////////////////////////////reworked traits - namespace { - - using lib::meta::Strip; - using std::is_convertible; - using std::is_arithmetic; - using std::is_same; - using std::__not_; - using std::__and_; - using std::__or_; - - template - struct is_basically - : is_same ::TypeReferred - ,typename Strip::TypeReferred> - { }; - - template - struct is_StringLike - : __or_< is_basically - , is_convertible - > - { }; - - template - struct can_lexical2string - : __or_< is_arithmetic - , is_StringLike - > - { }; - } - -namespace lib { -namespace meta { - template<> - struct Unwrap - { - typedef void Type; - }; -}} -/////////////////////////////////////////reworked traits - - - /////////////////////////////////////////planned new ostream inclusion namespace { diff --git a/src/lib/format-util.hpp b/src/lib/format-util.hpp index 985d04265..29d176d0d 100644 --- a/src/lib/format-util.hpp +++ b/src/lib/format-util.hpp @@ -57,7 +57,7 @@ namespace util { using boost::enable_if; - using lib::meta::can_ToString; + using lib::meta::can_convertToString; using lib::meta::can_lexical2string; using lib::meta::can_IterForEach; using lib::Symbol; @@ -77,13 +77,13 @@ namespace util { template - struct use_StringConversion : can_ToString { }; + struct use_StringConversion : can_convertToString { }; template struct use_LexicalConversion { enum { value = can_lexical2string::value - && !can_ToString::value + && !can_convertToString::value }; }; diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index d397150d1..89fe4cd02 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -61,7 +61,7 @@ ** can be used as a building block within this framework. ** ** - ** \par Lumiera forward iterator concept + ** # Lumiera forward iterator concept ** ** Similar to the STL, instead of using a common "Iterator" base class, ** we rather define a common set of functions and behaviour which can diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index d7c5b10a3..86675f1e4 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -21,6 +21,39 @@ */ +/** @file trait.hpp + ** Helpers for type detection, type rewriting and metaprogramming. + ** This header is a collection of frequently used templates for working with types. + ** It incurs only modest header inclusion overhead (be sure not to jeopardise that!). + ** + ** \par unwrapping + ** Strip away all kinds of type adornments, like const, reference, pointer, smart-ptr. + ** The accompanying \ref unwrap() function can be used to accept "stuff packaged + ** in various forms". The \ref Strip template packages this ability in various + ** degrees for metaprogramming + ** @warning these helpers can be quite dangerous, as they silently break + ** any protective barriers (including lifecycle managing smart-ptrs) + ** + ** \par string conversion + ** a set of trait templates to categorise arbitrary types with respect to + ** the ability for string conversions + ** + ** \par ability to iterate + ** these traits [can be used](util-foreach.hpp) to build the notion of a + ** generic container -- basically anything that can be enumerated. + ** Within Lumiera, we frequently use our own concept of "iterability", + ** known as ["Lumiera Forward Iterator"](iter-adapter.hpp). These + ** helpers here allow to unify this concept with the "Range" + ** concept from the standard library (`begin()` and `end()`) + ** + ** @see MetaUtils_test + ** @see \rem format-obj.hpp string representation for _anything_ + ** @see \ref lib/meta/utils.hpp very basic metaprogramming helpers + ** @see typelist.hpp + ** + */ + + #ifndef LIB_META_TRAIT_H #define LIB_META_TRAIT_H @@ -28,13 +61,8 @@ #include "lib/meta/util.hpp" #include "lib/meta/duck-detector.hpp" -#include -#include -#include -#include -#include +#include -#include //Forward declarations for the Unwrap helper.... namespace boost{ @@ -55,13 +83,23 @@ namespace mobject{ namespace lib { namespace meta { + using std::remove_cv; + using std::remove_pointer; + using std::remove_reference; + using std::is_convertible; + using std::is_arithmetic; + using std::is_same; + using std::__not_; + using std::__and_; + using std::__or_; /** - * Helper for type analysis: - * tries to extract a base type from various wrappers. + * Helper for type analysis and convenience accessors: + * attempts to extract a base type from various wrappers. * Additionally allows to extract/deref the wrapped element. * @warning strips away any const + * @warning also strips away smart-ptrs and lifecycle managers! */ template struct Unwrap @@ -75,10 +113,16 @@ namespace meta { } }; + template<> + struct Unwrap ///< @note we can't unwrap void! + { + typedef void Type; + }; + template struct Unwrap { - typedef typename boost::remove_cv::type Type; + typedef typename std::remove_cv::type Type; static Type& extract (const X* ptr) @@ -173,10 +217,10 @@ namespace meta { template struct Strip { - typedef typename boost::remove_cv ::type TypeUnconst; - typedef typename boost::remove_reference::type TypeReferred; - typedef typename boost::remove_pointer ::type TypePointee; - typedef typename boost::remove_cv ::type TypePlain; + typedef typename std::remove_cv ::type TypeUnconst; + typedef typename std::remove_reference::type TypeReferred; + typedef typename std::remove_pointer ::type TypePointee; + typedef typename std::remove_cv ::type TypePlain; typedef typename Unwrap ::Type Type; }; @@ -218,41 +262,52 @@ namespace meta { + /* ==== Traits ==== */ + /** compare unadorned types, disregarding const and references */ + template + struct is_basically + : is_same ::TypeReferred + ,typename Strip::TypeReferred> + { }; - /** Trait template for detecting if a type can be converted to string. - * For example, this allows to write specialisations with the help of - * boost::enable_if - */ - template - struct can_ToString - { - enum { value = boost::is_convertible::value - }; - }; + /** detect various flavours of string / text data */ + template + struct is_StringLike + : __or_< is_basically + , is_convertible + > + { }; - - /** Trait template for guarding \c lexical_cast<..> expressions. - * Such an expression won't even compile for some types, because of - * missing or ambiguous output operator(s). - * Ideally, there would be some automatic detection (relying on the - * existence of an operator<< for the given type. But I couldn't make - * this work, so I fell back on just declaring types which are known - * to work with lexical_cast to string - * @note this compile-time trait can't predict if such an conversion - * to string will be successful at runtime; indeed it may throw, - * so you should additionally guard the invocation with try-catch! + /** types able to be lexically converted to string representation + * @note this compile-time trait can't predict if such an conversion + * to string will be successful at runtime; indeed it may throw, + * so you should additionally guard the invocation with try-catch! + * @remarks this template is relevant for guarding `lexical_cast<..>` expressions. + * Such an expression won't even compile for some types, because of missing or + * ambiguous output operator(s). Ideally, there would be some automatic detection + * (relying on the existence of an `operator<<` for the given type. But at my + * first attempt in 2009 (commit 1533e5bd0) I couldn't make this work, so I + * fell back on just declaring all classes of types which are known to work + * with lexical_cast to string. + * @remarks Meanwhile (2016) I think this is an adequate and robust solution + * and here to stay. Based on this, I'll add a generic overload for the + * output stream inserter `operator<<` to use custom string conversions; + * this trait is essential to exclude types which can be printed as-is. */ template struct can_lexical2string - { - enum { value = boost::is_arithmetic::value - }; - }; + : __or_< is_arithmetic + , is_StringLike + > + { }; + + /* ====== generic iteration support ====== */ + /** Trait template to detect a type usable immediately as * "Lumiera Forward Iterator" in a specialised for-each loop * This is just a heuristic, based on some common properties @@ -269,7 +324,7 @@ namespace meta { META_DETECT_OPERATOR_INC(); public: - enum{ value = boost::is_convertible::value + enum{ value = std::is_convertible::value && HasNested_value_type::value && HasOperator_deref::value && HasOperator_inc::value