Newer
Older
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_TYPETRAITS_HH
#define DUNE_TYPETRAITS_HH
#if defined HAVE_TYPE_TRAITS
#include <type_traits>
#elif defined HAVE_TR1_TYPE_TRAITS
#include <tr1/type_traits>
#endif
namespace Dune
{
/**
* @file
* @brief Traits for type conversions and type information.
* @author Markus Blatt, Christian Engwer
*/
/** @addtogroup Common
*
* @{
*/
/**
* @brief Just an empty class
*/
struct Empty {};
/**
* @brief General type traits class to check whether type is reference or
* pointer type
*
* \deprecated This class will be replaced by alternatives found in the C++11 stl.
* - Use is_pointer<T>::value instead of TypeTraits<T>::isPointer
* - Use is_lvalue_reference<T>::value instead of TypeTraits<T>::isReference
* - Use remove_pointer<T>::type instead of TypeTraits<T>::PointeeType
* - Use remove_reference<T>::type instead of TypeTraits<T>::ReferredType
*/
template <typename T>
class TypeTraits
{
private:
template <class U>
struct PointerTraits {
enum { result = false };
typedef Empty PointeeType;
};
template <class U>
struct PointerTraits<U*> {
enum { result = true };
typedef U PointeeType;
};
template <class U> struct ReferenceTraits
{
enum { result = false };
typedef U ReferredType;
};
template <class U> struct ReferenceTraits<U&>
{
enum { result = true };
typedef U ReferredType;
};
public:
enum { isPointer = PointerTraits<T>::result };
typedef typename PointerTraits<T>::PointeeType PointeeType DUNE_DEPRECATED_MSG("Use remove_pointer instead!");
enum { isReference = ReferenceTraits<T>::result };
typedef typename ReferenceTraits<T>::ReferredType ReferredType DUNE_DEPRECATED_MSG("Use remove_reference instead!");
/**
* @brief Determines wether a type is const or volatile and provides the
* unqualified types.
*/
template<typename T>
struct ConstantVolatileTraits
{
enum {
/** @brief True if T has a volatile specifier. */
isVolatile=false,
/** @brief True if T has a const qualifier. */
isConst=false
};
/** @brief The unqualified type. */
typedef T UnqualifiedType;
/** @brief The const type. */
typedef const T ConstType;
/** @brief The const volatile type. */
typedef const volatile T ConstVolatileType;
};
template<typename T>
struct ConstantVolatileTraits<const T>
{
enum {
isVolatile=false, isConst=true
};
typedef T UnqualifiedType;
typedef const UnqualifiedType ConstType;
typedef const volatile UnqualifiedType ConstVolatileType;
};
template<typename T>
struct ConstantVolatileTraits<volatile T>
{
enum {
isVolatile=true, isConst=false
};
typedef T UnqualifiedType;
typedef const UnqualifiedType ConstType;
typedef const volatile UnqualifiedType ConstVolatileType;
};
template<typename T>
struct ConstantVolatileTraits<const volatile T>
{
enum {
isVolatile=true, isConst=true
};
typedef T UnqualifiedType;
typedef const UnqualifiedType ConstType;
typedef const volatile UnqualifiedType ConstVolatileType;
};
/** @brief Tests wether a type is volatile. */
template<typename T>
struct IsVolatile
{
enum {
/** @brief True if The type is volatile. */
value=ConstantVolatileTraits<T>::isVolatile
};
};
/** @brief Tests wether a type is constant. */
template<typename T>
struct IsConst
{
enum {
/** @brief True if The type is constant. */
value=ConstantVolatileTraits<T>::isConst
};
};
template<typename T, bool isVolatile>
struct RemoveConstHelper
{
typedef typename ConstantVolatileTraits<T>::UnqualifiedType Type;
};
template<typename T>
struct RemoveConstHelper<T,true>
{
typedef volatile typename ConstantVolatileTraits<T>::UnqualifiedType Type;
};
#if defined HAVE_TYPE_TRAITS
using std::remove_const;
#elif defined HAVE_TR1_TYPE_TRAITS
using std::tr1::remove_const;
Oliver Sander
committed
#else
/**
* @brief Removes a const qualifier while preserving others.
*/
template<typename T>
struct remove_const
{
typedef typename RemoveConstHelper<T, IsVolatile<T>::value>::Type type;
};
#endif
#if defined HAVE_TYPE_TRAITS
using std::remove_reference;
#elif defined HAVE_TR1_TYPE_TRAITS
using std::tr1::remove_reference;
#else
//! Remove a reference from a type
/**
* If the template parameter \c T matches \c T1&, then the member typedef \c
* type is \c T1, otherwise it is \c T.
*/
template<typename T> struct remove_reference {
//! T with references removed
typedef T type;
};
# ifndef DOXYGEN
template<typename T> struct remove_reference<T&> {
typedef T type;
};
# endif // ! defined(DOXYGEN)
#endif
* @brief Checks wether a type is convertible to another.
*
* @tparam From type you want to convert
* @tparam To type you want to obtain
*
* Inspired by
* <A HREF="http://www.kotiposti.net/epulkkin/instructive/base-class-determination.html"> this website</A>
*/
template<class From, class To>
class Conversion
{
typedef char Small;
struct Big {char dummy[2];};
static Small test(To);
static Big test(...);
static typename remove_reference< From >::type &makeFrom ();
enum {
/** @brief True if the conversion exists. */
exists = sizeof(test(makeFrom())) == sizeof(Small),
Oliver Sander
committed
/** @brief Whether the conversion exists in both ways. */
/** @brief True if To and From are the same type. */
sameType = false
};
Conversion(){}
template <class From>
class Conversion<From, void>
{
public:
enum {
exists = false,
isTwoWay = false,
sameType = false
};
};
template <class To>
class Conversion<void, To>
{
public:
enum {
exists = false,
isTwoWay = false,
sameType = false
};
};
Martin Nolte
committed
template<>
class Conversion< int, double >
{
public:
enum {
exists = true,
isTwoWay = false,
sameType = false
};
};
template<class T>
class Conversion<T,T>{
public:
enum { exists=true, isTwoWay=true, sameType=true};
/**
* @brief Checks wether a type is derived from another.
*
* @tparam Base the potential base class you want to test for
* @tparam Derived type you want to test
*
* Similar idea to
* <A HREF="http://www.kotiposti.net/epulkkin/instructive/base-class-determination.html"> this website</A>
*/
template <class Base, class Derived>
class IsBaseOf
{
typedef typename ConstantVolatileTraits< typename remove_reference< Base >::type >::UnqualifiedType RawBase;
typedef typename ConstantVolatileTraits< typename remove_reference< Derived >::type >::UnqualifiedType RawDerived;
typedef char Small;
struct Big {char dummy[2];};
static Small test(RawBase*);
static RawDerived* &makePtr ();
public:
enum {
/** @brief True if Base is a base class of Derived. */
value = sizeof(test(makePtr())) == sizeof(Small)
};
IsBaseOf(){}
/**
* @brief Checks wether two types are interoperable.
*
* Two types are interoperable if conversions in either directions
* exists.
*/
template<class T1, class T2>
struct IsInteroperable
{
enum {
/**
* @brief True if either a conversion from T1 to T2 or vice versa
* exists.
*/
value = Conversion<T1,T2>::exists || Conversion<T2,T1>::exists
Oliver Sander
committed
#ifdef HAVE_TYPE_TRAITS
using std::enable_if;
#else
/**
* @brief Enable typedef if condition is met.
*
* Replacement implementation for compilers without this in the stl.
* Depending on the value of b the type T is provided as typedef type.
*/
template<bool b, typename T=void>
struct enable_if
{
typedef T type;
};
template<typename T>
struct enable_if<false,T>
Oliver Sander
committed
#endif
/**
* @brief Enable typedef if two types are interoperable.
*
* (also see IsInteroperable)
*/
template<class T1, class T2, class Type>
struct EnableIfInterOperable
: public enable_if<IsInteroperable<T1,T2>::value, Type>
#if defined HAVE_TYPE_TRAITS
using std::is_same;
#elif defined HAVE_TR1_TYPE_TRAITS
using std::tr1::is_same;
#else
/**
* @brief Compile time test for testing whether
* two types are the same.
*/
template<typename T1, typename T2>
struct is_same
{
//! Whether T1 is the same type as T2.
enum {
/* @brief Whether T1 is the same type as T2. */
value=false
};
};
template<typename T>
struct is_same<T,T>
{
enum { value=true};
};
#endif
/**
* @brief Select a type based on a condition.
*
* If template parameter first is true T1 is selected
* otherwise T2 will be selected.
*
* \deprecated Will be removed after dune-common-2.3, use 'conditional' instead.
*/
template<bool first, class T1, class T2>
struct SelectType
{
/**
* @brief The selected type.
*
* if first is true this will be type T1 and
* otherwise T2
*/
typedef T1 Type DUNE_DEPRECATED_MSG("Use Dune::conditional::type instead");
} DUNE_DEPRECATED;
template<class T1, class T2>
struct SelectType<false,T1,T2>
{
typedef T2 Type DUNE_DEPRECATED_MSG("Use Dune::conditional::type instead");
#if DOXYGEN || !HAVE_STD_CONDITIONAL
/**
* @brief Select a type based on a condition.
*
* If template parameter first is true T1 is selected
* otherwise T2 will be selected.
* The selected type is accessible through the typedef
* type.
*
* \note If available, this uses C++11 std::conditional, otherwise it provides
* a reimplementation.
*/
template<bool first, class T1, class T2>
struct conditional
{
/**
* @brief The selected type
*
* if first is true this will be type T1 and
* T2 otherwise
*/
typedef T1 type;
};
template<class T1, class T2>
struct conditional<false,T1,T2>
{
typedef T2 type;
// pull in default implementation
using std::conditional;
////////////////////////////////////////////////////////////////////////
//
// integral_constant (C++0x 20.7.3 "Helper classes")
//
#if HAVE_INTEGRAL_CONSTANT
using std::integral_constant;
using std::true_type;
using std::false_type;
#else // #if HAVE_INTEGRAL_CONSTANT
//! Generate a type for a given integral constant
/**
* \tparam T Type of the constant.
* \tparam v Value of the constant.
*/
template <class T, T v>
struct integral_constant {
//! value this type was generated for
static const T value = v;
//! type of value
typedef T value_type;
//! type of this class itself
typedef integral_constant<T,v> type;
//! conversion to value_type/T
operator value_type() { return value; }
};
//! type for true
typedef integral_constant<bool, true> true_type;
//! type for false
typedef integral_constant<bool, false> false_type;
#endif // #else // #if HAVE_INTEGRAL_CONSTANT
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
template<typename>
struct __is_pointer_helper
: public false_type { };
template<typename T>
struct __is_pointer_helper<T*>
: public true_type { };
/// is_pointer
template<typename T>
struct is_pointer
: public integral_constant<bool, (__is_pointer_helper<T>::value)>
{ };
// Helper class for is_lvalue_reference
template<typename>
struct __is_lvalue_reference_helper
: public false_type { };
template<typename T>
struct __is_lvalue_reference_helper<T&>
: public true_type { };
/** \brief Determine whether a type is a lvalue reference type */
template<typename T>
struct is_lvalue_reference
: public integral_constant<bool, (__is_lvalue_reference_helper<T>::value)>
{ };
template<typename _Tp>
struct __remove_pointer_helper
{ typedef _Tp type; };
template<typename _Tp>
struct __remove_pointer_helper<_Tp*>
{ typedef _Tp type; };
/** \brief Return the type a pointer type points to
*
* \note When the argument T is not a pointer, TypeTraits::PointeeType returns Dune::Empty,
* while Dune::remove_pointer (as std::remove_pointer), returns T itself.
*/
template<typename _Tp>
struct remove_pointer
: public __remove_pointer_helper<typename remove_const<_Tp>::type >
{ };
/** @} */
}
#endif