type-traits(#985): rework and clean-up our type-traits
include the improved facility to detect the ability for lexical cast. Also remove the boost dependency and switch entirely to standard <type_traits>
This commit is contained in:
parent
e443fd79fd
commit
1814b1fc69
4 changed files with 103 additions and 87 deletions
|
|
@ -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<X> 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<typename T, typename U>
|
||||
struct is_basically
|
||||
: is_same <typename Strip<T>::TypeReferred
|
||||
,typename Strip<U>::TypeReferred>
|
||||
{ };
|
||||
|
||||
template<typename X>
|
||||
struct is_StringLike
|
||||
: __or_< is_basically<X, string>
|
||||
, is_convertible<X, const char*>
|
||||
>
|
||||
{ };
|
||||
|
||||
template<typename X>
|
||||
struct can_lexical2string
|
||||
: __or_< is_arithmetic<X>
|
||||
, is_StringLike<X>
|
||||
>
|
||||
{ };
|
||||
}
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
template<>
|
||||
struct Unwrap<void>
|
||||
{
|
||||
typedef void Type;
|
||||
};
|
||||
}}
|
||||
/////////////////////////////////////////reworked traits
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////planned new ostream inclusion
|
||||
namespace {
|
||||
|
||||
|
|
|
|||
|
|
@ -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<typename X>
|
||||
struct use_StringConversion : can_ToString<X> { };
|
||||
struct use_StringConversion : can_convertToString<X> { };
|
||||
|
||||
template<typename X>
|
||||
struct use_LexicalConversion
|
||||
{
|
||||
enum { value = can_lexical2string<X>::value
|
||||
&& !can_ToString<X>::value
|
||||
&& !can_convertToString<X>::value
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#include <string>
|
||||
|
||||
//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<typename X>
|
||||
struct Unwrap
|
||||
|
|
@ -75,10 +113,16 @@ namespace meta {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Unwrap<void> ///< @note we can't unwrap void!
|
||||
{
|
||||
typedef void Type;
|
||||
};
|
||||
|
||||
template<typename X>
|
||||
struct Unwrap<X*>
|
||||
{
|
||||
typedef typename boost::remove_cv<X>::type Type;
|
||||
typedef typename std::remove_cv<X>::type Type;
|
||||
|
||||
static Type&
|
||||
extract (const X* ptr)
|
||||
|
|
@ -173,10 +217,10 @@ namespace meta {
|
|||
template<typename X>
|
||||
struct Strip
|
||||
{
|
||||
typedef typename boost::remove_cv<X> ::type TypeUnconst;
|
||||
typedef typename boost::remove_reference<TypeUnconst>::type TypeReferred;
|
||||
typedef typename boost::remove_pointer<TypeReferred> ::type TypePointee;
|
||||
typedef typename boost::remove_cv<TypePointee> ::type TypePlain;
|
||||
typedef typename std::remove_cv<X> ::type TypeUnconst;
|
||||
typedef typename std::remove_reference<TypeUnconst>::type TypeReferred;
|
||||
typedef typename std::remove_pointer<TypeReferred> ::type TypePointee;
|
||||
typedef typename std::remove_cv<TypePointee> ::type TypePlain;
|
||||
|
||||
typedef typename Unwrap<TypePlain> ::Type Type;
|
||||
};
|
||||
|
|
@ -218,41 +262,52 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
/* ==== Traits ==== */
|
||||
|
||||
/** compare unadorned types, disregarding const and references */
|
||||
template<typename T, typename U>
|
||||
struct is_basically
|
||||
: is_same <typename Strip<T>::TypeReferred
|
||||
,typename Strip<U>::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 <typename TY>
|
||||
struct can_ToString
|
||||
{
|
||||
enum { value = boost::is_convertible<TY, std::string>::value
|
||||
};
|
||||
};
|
||||
/** detect various flavours of string / text data */
|
||||
template<typename X>
|
||||
struct is_StringLike
|
||||
: __or_< is_basically<X, std::string>
|
||||
, is_convertible<X, const char*>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
/** 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<typename X>
|
||||
struct can_lexical2string
|
||||
{
|
||||
enum { value = boost::is_arithmetic<X>::value
|
||||
};
|
||||
};
|
||||
: __or_< is_arithmetic<X>
|
||||
, is_StringLike<X>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ====== 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<Type, bool>::value
|
||||
enum{ value = std::is_convertible<Type, bool>::value
|
||||
&& HasNested_value_type<Type>::value
|
||||
&& HasOperator_deref<Type>::value
|
||||
&& HasOperator_inc<Type>::value
|
||||
|
|
|
|||
Loading…
Reference in a new issue