Skip to content
Snippets Groups Projects
typetraits.hh 14.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • // -*- 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
    
    Martin Nolte's avatar
    Martin Nolte committed
    #include <dune/common/deprecated.hh>
    
    #include <dune/common/std/utility.hh>
    
    namespace Dune
    {
    
      /**
       * @file
       * @brief Traits for type conversions and type information.
    
       * @author Markus Blatt, Christian Engwer
    
    
      /**
       * @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;
      };
    
    
       * @brief Checks wether a type is convertible to another.
       *
       * @tparam From type you want to convert
       * @tparam To type you want to obtain
    
    Oliver Sander's avatar
    Oliver Sander committed
       * <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),
    
          /** @brief Whether the conversion exists in both ways. */
    
    Markus Blatt's avatar
    Markus Blatt committed
          isTwoWay = exists && Conversion<To,From>::exists,
    
          /** @brief True if To and From are the same type. */
          sameType = false
        };
    
      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
        };
      };
    
    
      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 Big test(...);
    
        static RawDerived* &makePtr ();
    
      public:
        enum {
          /** @brief True if Base is a base class of Derived. */
          value = sizeof(test(makePtr())) == sizeof(Small)
        };
    
      /**
       * @brief Checks wether two types are interoperable.
       *
    
    Christian Engwer's avatar
    Christian Engwer committed
       * 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
    
    Christian Engwer's avatar
    Christian Engwer committed
      /**
       * @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>
    
      // pull in default implementation
    
      using std::integral_constant;
      using std::true_type;
      using std::false_type;
    
    
    
      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 >
        { };
    
    
      /**
         \brief template which always yields a false value
         \tparam T Some type.  It sould be a type expression involving template
                   parameters of the class or function using AlwaysFalse.
    
         Suppose you have a template class.  You want to document the required
         members of this class in the non-specialized template, but you know that
         actually instantiating the non-specialized template is an error.  You
         can try something like this:
         \code
         template<typename T>
         struct Traits {
           static_assert(false,
                              "Instanciating this non-specialized template is an "
                              "error.  You should use one of the specializations "
                              "instead.");
           //! The type used to frobnicate T
           typedef void FrobnicateType;
         };
         \endcode
         This will trigger static_assert() as soon as the compiler reads the
         definition for the Traits template, since it knows that "false" can
         never become true, no matter what the template parameters of Traits are.
         As a workaround you can use AlwaysFalse: replace <tt>false</tt> by
         <tt>AlwaysFalse<T>::value</tt>, like this:
         \code
         template<typename T>
         struct Traits {
           static_assert(AlwaysFalse<T>::value,
                              "Instanciating this non-specialized template is an "
                              "error.  You should use one of the specializations "
                              "instead.");
           //! The type used to frobnicate T
           typedef void FrobnicateType;
         };
         \endcode
         Since there might be an specialization of AlwaysFalse for template
         parameter T, the compiler cannot trigger static_assert() until the
         type of T is known, that is, until Traits<T> is instantiated.
       */
      template<typename T>
      struct AlwaysFalse {
        //! always a false value
        static const bool value = false;
      };
    
      /**
         \brief template which always yields a true value
         \tparam T Some type.  It sould be a type expression involving template
                   parameters of the class or function using AlwaysTrue.
    
         \note This class exists mostly for consistency with AlwaysFalse.
       */
      template<typename T>
      struct AlwaysTrue {
        //! always a true value
        static const bool value = true;
      };
    
    
    #if defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT
    
    #ifndef DOXYGEN
    
      namespace detail {
    
        template<typename T, typename I, typename = int>
        struct _is_indexable
          : public std::false_type
        {};
    
    
        template<typename T, typename I>
    
        struct _is_indexable<T,I,typename std::enable_if<(sizeof(Std::declval<T>()[Std::declval<I>()]) > 0),int>::type>
          : public std::true_type
        {};
    
      //! Type trait to determine whether an instance of T has an operator[](I), i.e. whether
      //! it can be indexed with an index of type I.
    
      /**
       * \warning Not all compilers support testing for arbitrary index types. In particular, there
       *          are problems with GCC 4.4 and 4.5.
       */
    
      template<typename T, typename I = std::size_t>
      struct is_indexable
    
    
    #else // defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT
    
    
      // okay, here follows a mess of compiler bug workarounds...
      // GCC 4.4 dies if we try to subscript a simple type like int and
      // both GCC 4.4 and 4.5 don't like using arbitrary types as subscripts
      // for macros.
      // So we make sure to only ever attempt the SFINAE for operator[] for
      // class types, and to make sure the compiler doesn't become overly eager
      // we have to do some lazy evaluation tricks with nested templates and
      // stuff.
      // Let's get rid of GCC 4.4 ASAP!
    
    
      namespace detail {
    
        // simple wrapper template to support the lazy evaluation required
        // in _is_indexable
        template<typename T>
        struct _lazy
        {
          template<typename U>
          struct evaluate
          {
            typedef T type;
          };
        };
    
        // default version, gets picked if SFINAE fails
        template<typename T, typename = int>
        struct _is_indexable
          : public std::false_type
        {};
    
        // version for types supporting the subscript operation
        template<typename T>
        struct _is_indexable<T,decltype(Std::declval<T>()[0],0)>
          : public std::true_type
        {};
    
        // helper struct for delaying the evaluation until we are sure
        // that T is a class (i.e. until we are outside std::conditional
        // below)
        struct _check_for_index_operator
        {
    
          template<typename T>
          struct evaluate
            : public _is_indexable<T>
          {};
    
        };
    
      }
    
      // The rationale here is as follows:
      // 1) If we have an array, we assume we can index into it. That isn't
      //    true if I isn't an integral type, but that's why we have the static assertion
      //    in the body - we could of course try and check whether I is integral, but I
      //    can't be arsed and want to provide a motivation to switch to a newer compiler...
      // 2) If we have a class, we use SFINAE to check for operator[]
      // 3) Otherwise, we assume that T does not support indexing
      //
      // In order to make sure that the compiler doesn't accidentally try the SFINAE evaluation
      // on an array or a scalar, we have to resort to lazy evaluation.
      template<typename T, typename I = std::size_t>
      struct is_indexable
        : public std::conditional<
                   std::is_array<T>::value,
                   detail::_lazy<std::true_type>,
                   typename std::conditional<
                     std::is_class<T>::value,
                     detail::_check_for_index_operator,
                     detail::_lazy<std::false_type>
                     >::type
                   >::type::template evaluate<T>::type
      {
        static_assert(std::is_same<I,std::size_t>::value,"Your compiler is broken and does not support checking for arbitrary index types");
      };
    
    
    #endif // defined(DOXYGEN) or HAVE_IS_INDEXABLE_SUPPORT