///\file

/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com

Copyright(c) 2014 jwellbelove

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/

#if 0
#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
#endif

//***************************************************************************
// THIS FILE HAS BEEN AUTO GENERATED. DO NOT EDIT THIS FILE.
//***************************************************************************

//***************************************************************************
// To generate to header file, run this at the command line.
// Note: You will need Python and COG installed.
//
// python -m cogapp -d -e -otypes.h -DHandlers=<n> types_generator.h
// Where <n> is the number of types to support.
//
// e.g.
// To generate handlers for up to 16 types...
// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h
//
// See generate.bat
//***************************************************************************

#ifndef ETL_TYPE_TRAITS_INCLUDED
#define ETL_TYPE_TRAITS_INCLUDED

#include <stddef.h>
#include <stdint.h>

#include "platform.h"
#include "nullptr.h"
#include "static_assert.h"

///\defgroup type_traits type_traits
/// A set of type traits definitions.
/// Derived from either the standard or alternate definitions, dependant on whether or not ETL_NO_STL is defined.
/// \ingroup utilities

#if ETL_USING_STL && ETL_CPP11_SUPPORTED
  #include <type_traits>
#endif

namespace etl
{
#if ETL_NOT_USING_STL || ETL_CPP11_NOT_SUPPORTED

  //*****************************************************************************
  // Traits are defined by the ETL
  //*****************************************************************************
  //***************************************************************************
  /// integral_constant
  template <typename T, const T VALUE>
  struct integral_constant
  {
    static const T value = VALUE;

    typedef T value_type;
    typedef integral_constant<T, VALUE> type;

    operator value_type() const
    {
      return value;
    }
  };

  /// integral_constant specialisations
  typedef integral_constant<bool, false> false_type;
  typedef integral_constant<bool, true>  true_type;

  template <typename T, const T VALUE>
  const T integral_constant<T, VALUE>::value;

#if ETL_CPP11_SUPPORTED
  template <bool B>
  using bool_constant = integral_constant<bool, B>;
#else
  template <bool B>
  struct bool_constant : etl::integral_constant<bool, B> { };
#endif

  //***************************************************************************
  /// negation
  template <typename T>
  struct negation : etl::bool_constant<!bool(T::value)>
  {
  };

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool negation_v = negation<T>::value;
#endif

  //***************************************************************************
  /// remove_reference
  template <typename T> struct remove_reference { typedef T type; };
  template <typename T> struct remove_reference<T&> { typedef T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_reference_t = typename remove_reference<T>::type;
#endif

  //***************************************************************************
  /// remove_pointer
  template <typename T> struct remove_pointer { typedef T type; };
  template <typename T> struct remove_pointer<T*> { typedef T type; };
  template <typename T> struct remove_pointer<const T*> { typedef const T type; };
  template <typename T> struct remove_pointer<volatile T*> { typedef volatile T type; };
  template <typename T> struct remove_pointer<const volatile T*> { typedef const volatile T type; };
  template <typename T> struct remove_pointer<T* const> { typedef T type; };
  template <typename T> struct remove_pointer<const T* const> { typedef const T type; };
  template <typename T> struct remove_pointer<volatile T* const> { typedef volatile T type; };
  template <typename T> struct remove_pointer<const volatile T* const> { typedef const volatile T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_pointer_t = typename remove_pointer<T>::type;
#endif

  //***************************************************************************
  /// add_pointer
  template <typename T> struct add_pointer { typedef typename remove_reference<T>::type* type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_pointer_t = typename add_pointer<T>::type;
#endif

  //***************************************************************************
  /// is_const
  template <typename T> struct is_const : false_type {};
  template <typename T> struct is_const<const T> : true_type {};
  template <typename T> struct is_const<const volatile T> : true_type {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_const_v = is_const<T>::value;
#endif

  //***************************************************************************
  /// remove_const
  template <typename T> struct remove_const { typedef T type; };
  template <typename T> struct remove_const<const T> { typedef T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_const_t = typename remove_const<T>::type;
#endif

  //***************************************************************************
  /// add_const
  template <typename T> struct add_const { typedef const T type; };
  template <typename T> struct add_const<const T> { typedef const T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_const_t = typename add_const<T>::type;
#endif

  //***************************************************************************
  /// is_volatile
  template <typename T> struct is_volatile : false_type {};
  template <typename T> struct is_volatile<volatile T> : true_type {};
  template <typename T> struct is_volatile<const volatile T> : true_type {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_volatile_v = is_volatile<T>::value;
#endif

  //***************************************************************************
  /// remove_volatile
  template <typename T> struct remove_volatile { typedef T type; };
  template <typename T> struct remove_volatile<volatile T> { typedef T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_volatile_t = typename remove_volatile<T>::type;
#endif

  //***************************************************************************
  /// add_volatile
  template <typename T> struct add_volatile { typedef volatile T type; };
  template <typename T> struct add_volatile<volatile T> { typedef volatile T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_volatile_t = typename add_volatile<T>::type;
#endif

  //***************************************************************************
  /// remove_cv
  template <typename T> struct remove_cv
  {
    typedef typename remove_volatile<typename remove_const<T>::type>::type type;
  };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_cv_t = typename remove_cv<T>::type;
#endif

  //***************************************************************************
  /// add_cv
  template <typename T> struct add_cv
  {
    typedef typename add_volatile<typename add_const<T>::type>::type type;
  };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_cv_t = typename add_cv<T>::type;
#endif

  //***************************************************************************
  /// is_integral
  template <typename T> struct is_integral : false_type {};
  template <> struct is_integral<bool> : true_type {};
  template <> struct is_integral<char> : true_type {};
  template <> struct is_integral<unsigned char> : true_type {};
  template <> struct is_integral<signed char> : true_type {};
  template <> struct is_integral<wchar_t> : true_type {};
  template <> struct is_integral<short> : true_type {};
  template <> struct is_integral<unsigned short> : true_type {};
  template <> struct is_integral<int> : true_type {};
  template <> struct is_integral<unsigned int> : true_type {};
  template <> struct is_integral<long> : true_type {};
  template <> struct is_integral<unsigned long> : true_type {};
  template <> struct is_integral<long long> : true_type {};
  template <> struct is_integral<unsigned long long> : true_type {};
  template <typename T> struct is_integral<const T> : is_integral<T> {};
  template <typename T> struct is_integral<volatile T> : is_integral<T> {};
  template <typename T> struct is_integral<const volatile T> : is_integral<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_integral_v = is_integral<T>::value;
#endif

  //***************************************************************************
  /// is_signed
  template <typename T> struct is_signed : false_type {};
  template <> struct is_signed<char> : integral_constant<bool, (char(255) < 0)> {};
  template <> struct is_signed<wchar_t> : public etl::integral_constant<bool, static_cast<bool>(wchar_t(-1) < wchar_t(0))> {};
  template <> struct is_signed<signed char> : true_type {};
  template <> struct is_signed<short> : true_type {};
  template <> struct is_signed<int> : true_type {};
  template <> struct is_signed<long> : true_type {};
  template <> struct is_signed<long long> : true_type {};
  template <> struct is_signed<float> : true_type {};
  template <> struct is_signed<double> : true_type {};
  template <> struct is_signed<long double> : true_type {};
  template <typename T> struct is_signed<const T> : is_signed<T> {};
  template <typename T> struct is_signed<volatile T> : is_signed<T> {};
  template <typename T> struct is_signed<const volatile T> : is_signed<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_signed_v = is_signed<T>::value;
#endif

  //***************************************************************************
  /// is_unsigned
  template <typename T> struct is_unsigned : false_type {};
  template <> struct is_unsigned<bool> : true_type {};
  template <> struct is_unsigned<char> : integral_constant<bool, (char(255) > 0)> {};
  template <> struct is_unsigned<unsigned char> : true_type {};
  template <> struct is_unsigned<wchar_t> : public etl::integral_constant<bool, (wchar_t(-1) > wchar_t(0))> {};
  template <> struct is_unsigned<unsigned short> : true_type {};
  template <> struct is_unsigned<unsigned int> : true_type {};
  template <> struct is_unsigned<unsigned long> : true_type {};
  template <> struct is_unsigned<unsigned long long> : true_type {};
  template <typename T> struct is_unsigned<const T> : is_unsigned<T> {};
  template <typename T> struct is_unsigned<volatile T> : is_unsigned<T> {};
  template <typename T> struct is_unsigned<const volatile T> : is_unsigned<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
#endif

  //***************************************************************************
  /// is_floating_point
  template <typename T> struct is_floating_point : false_type {};
  template <> struct is_floating_point<float> : true_type {};
  template <> struct is_floating_point<double> : true_type {};
  template <> struct is_floating_point<long double> : true_type {};
  template <typename T> struct is_floating_point<const T> : is_floating_point<T> {};
  template <typename T> struct is_floating_point<volatile T> : is_floating_point<T> {};
  template <typename T> struct is_floating_point<const volatile T> : is_floating_point<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_floating_point_v = is_floating_point<T>::value;
#endif

  //***************************************************************************
  /// is_same
  template <typename T1, typename T2> struct is_same : public false_type {};
  template <typename T> struct is_same<T, T> : public true_type {};

#if ETL_CPP17_SUPPORTED
  template <typename T1, typename T2>
  inline constexpr bool is_same_v = is_same<T1, T2>::value;
#endif

  //***************************************************************************
  /// is_void
  template<typename T> struct is_void : false_type {};
  template<> struct is_void<void> : true_type {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_void_v = is_void<T>::value;
#endif

  //***************************************************************************
  /// is_arithmetic
  template<typename T> struct is_arithmetic : integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
#endif

  //***************************************************************************
  /// is_fundamental
  template <typename T> struct is_fundamental : integral_constant<bool, is_arithmetic<T>::value || is_void<T>::value> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_fundamental_v = is_fundamental<T>::value;
#endif

  //***************************************************************************
  /// is_compound
  template <typename T> struct is_compound : integral_constant<bool, !is_fundamental<T>::value> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_compound_v = is_compound<T>::value;
#endif

  //***************************************************************************
  /// is_array
  template <typename T> struct is_array : false_type {};
  template <typename T> struct is_array<T[]> : true_type {};
  template <typename T, size_t MAXN> struct is_array<T[MAXN]> : true_type {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_array_v = is_array<T>::value;
#endif

  //***************************************************************************
  /// is_pointer
  template<typename T> struct is_pointer_helper : false_type {};
  template<typename T> struct is_pointer_helper<T*> : true_type {};
  template<typename T> struct is_pointer : is_pointer_helper<typename remove_cv<T>::type> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_pointer_v = is_pointer<T>::value;
#endif

  //***************************************************************************
  /// is_reference
  template<typename T> struct is_reference_helper : false_type {};
  template<typename T> struct is_reference_helper<T&> : true_type {};
  template<typename T> struct is_reference : is_reference_helper<typename remove_cv<T>::type> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_reference_v = is_reference<T>::value;
#endif

  //***************************************************************************
  /// is_lvalue_reference
  template<typename T> struct is_lvalue_reference_helper : false_type {};
  template<typename T> struct is_lvalue_reference_helper<T&> : true_type {};
  template<typename T> struct is_lvalue_reference : is_lvalue_reference_helper<typename remove_cv<T>::type> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_lvalue_reference_v = etl::is_lvalue_reference<T>::value;
#endif

#if ETL_CPP11_SUPPORTED
  //***************************************************************************
  /// is_rvalue_reference
  template<typename T> struct is_rvalue_reference_helper : false_type {};
  template<typename T> struct is_rvalue_reference_helper<T&&> : true_type {};
  template<typename T> struct is_rvalue_reference : is_rvalue_reference_helper<typename remove_cv<T>::type> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_rvalue_reference_v = etl::is_rvalue_reference<T>::value;
#endif
#endif

  //***************************************************************************
  /// is_pod
  /// Only fundamental and pointers types are recognised.
  template <typename T> struct is_pod : etl::integral_constant<bool, etl::is_fundamental<T>::value || etl::is_pointer<T>::value> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_pod_v = etl::is_pod<T>::value;
#endif

  //***************************************************************************
  /// is_trivially_constructible
  /// Only POD types are recognised.
  template <typename T> struct is_trivially_constructible : etl::is_pod<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible<T>::value;
#endif

  //***************************************************************************
  /// is_trivially_copy_constructible
  /// Only POD types are recognised.
  template <typename T> struct is_trivially_copy_constructible : etl::is_pod<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_copy_constructible_v = etl::is_trivially_copy_constructible<T>::value;
#endif

  //***************************************************************************
  /// is_trivially_destructible
  /// Only POD types are recognised.
  template <typename T> struct is_trivially_destructible : etl::is_pod<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_destructible_v = etl::is_trivially_destructible<T>::value;
#endif

  //***************************************************************************
  /// is_trivially_copy_assignable
  /// Only POD types are recognised.
  template <typename T> struct is_trivially_copy_assignable : etl::is_pod<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_copy_assignable_v = etl::is_trivially_copy_assignable<T>::value;
#endif

  //***************************************************************************
  /// is_trivially_copyable
  /// Only POD types are recognised.
  template <typename T> struct is_trivially_copyable : etl::is_pod<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_copyable_v = etl::is_trivially_copyable<T>::value;
#endif

  //***************************************************************************
  /// conditional
  template <bool B, typename T, typename F>  struct conditional { typedef T type; };
  template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };

  //***************************************************************************
  /// make_signed
  template <typename T> struct make_signed { typedef  T type; };
  template <> struct make_signed<char> { typedef  signed char type; };
  template <> struct make_signed<unsigned char> { typedef  signed char type; };

  template <> struct make_signed<wchar_t>
  {
    typedef etl::conditional<sizeof(wchar_t) == sizeof(int16_t),
      int16_t,
      etl::conditional<sizeof(wchar_t) == sizeof(int32_t),
      int32_t,
      void>::type>::type type;
  };

  template <> struct make_signed<unsigned short> { typedef  short type; };
  template <> struct make_signed<unsigned int> { typedef int type; };
  template <> struct make_signed<unsigned long> { typedef  long type; };
  template <> struct make_signed<unsigned long long> { typedef long long type; };
  template <typename T> struct make_signed<const T> : add_const<typename make_signed<T>::type> {};
  template <typename T> struct make_signed<volatile T> : add_volatile<typename make_signed<T>::type> {};
  template <typename T> struct make_signed<const volatile T> : add_const<typename add_volatile<typename make_signed<T>::type>::type> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using make_signed_t = typename make_signed<T>::type;
#endif

  //***************************************************************************
  /// make_unsigned
  template <typename T> struct make_unsigned { typedef  T type; };
  template <> struct make_unsigned<char> { typedef unsigned char type; };
  template <> struct make_unsigned<signed char> { typedef unsigned char type; };
  template <> struct make_unsigned<short> { typedef unsigned short type; };

  template <> struct make_unsigned<wchar_t>
  {
    typedef etl::conditional<sizeof(wchar_t) == sizeof(uint16_t),
      uint16_t,
      etl::conditional<sizeof(wchar_t) == sizeof(uint32_t),
      uint32_t,
      void>::type>::type type;
  };

  template <> struct make_unsigned<int> { typedef unsigned int type; };
  template <> struct make_unsigned<long> { typedef unsigned long type; };
  template <> struct make_unsigned<long long> { typedef unsigned long long type; };
  template <typename T> struct make_unsigned<const T> : add_const<typename make_unsigned<T>::type> {};
  template <typename T> struct make_unsigned<volatile T> : add_volatile<typename make_unsigned<T>::type> {};
  template <typename T> struct make_unsigned<const volatile T> : add_const<typename add_volatile<typename make_unsigned<T>::type>::type> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using make_unsigned_t = typename make_unsigned<T>::type;
#endif

  //***************************************************************************
  /// enable_if
  template <bool B, typename T = void> struct enable_if {};
  template <typename T> struct enable_if<true, T> { typedef T type; };

#if ETL_CPP14_SUPPORTED
  template <bool B, typename T = void>
  using enable_if_t = typename enable_if<B, T>::type;
#endif

  //***************************************************************************
  /// extent
  template <typename T, size_t MAXN = 0U>
  struct extent : integral_constant<size_t, 0U> {};

  template <typename T>
  struct extent<T[], 0> : integral_constant<size_t, 0U> {};

  template <typename T, size_t MAXN>
  struct extent<T[], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};

  template <typename T, size_t MAXN>
  struct extent<T[MAXN], 0> : integral_constant<size_t, MAXN> {};

  template <typename T, size_t I, size_t MAXN>
  struct extent<T[I], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {};

#if ETL_CPP17_SUPPORTED
  template <typename T, size_t N = 0U>
  inline constexpr size_t extent_v = extent<T, N>::value;
#endif

  //***************************************************************************
  /// remove_extent
  template <typename T> struct remove_extent { typedef T type; };
  template <typename T> struct remove_extent<T[]> { typedef T type; };
  template <typename T, size_t MAXN> struct remove_extent<T[MAXN]> { typedef T type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_extent_t = typename remove_extent<T>::type;
#endif

  //***************************************************************************
  /// remove_all_extents
  template <typename T> struct remove_all_extents { typedef T type; };
  template <typename T> struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; };
  template <typename T, size_t MAXN> struct remove_all_extents<T[MAXN]> { typedef typename remove_all_extents<T>::type type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_all_extents_t = typename remove_all_extents<T>::type;
#endif

  //***************************************************************************
  /// rank
  template <typename T>struct rank : integral_constant<size_t, 0> {};
  template <typename T> struct rank<T[]> : public integral_constant<size_t, rank<T>::value + 1> {};
  template <typename T, size_t MAXN> struct rank<T[MAXN]> : public integral_constant<size_t, rank<T>::value + 1> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr size_t rank_v = rank<T>::value;
#endif

  //***************************************************************************
  /// decay
  template <typename T>
  struct decay
  {
    typedef typename etl::remove_reference<T>::type U;
    typedef typename etl::conditional<etl::is_array<U>::value,
      typename etl::remove_extent<U>::type*,
      typename etl::remove_cv<U>::type>::type type;
  };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using decay_t = typename decay<T>::type;
#endif

  //***************************************************************************
  /// is_base_of
  template<typename TBase,
           typename TDerived,
           const bool IsFundamental = (etl::is_fundamental<TBase>::value || etl::is_fundamental<TDerived>::value)>
  struct is_base_of
  {
  private:

    template<typename T> struct dummy {};
    struct internal: TDerived, dummy<int>{};

    static TBase* check(TBase*);
    template<typename T> static char check(dummy<T>*);

  public:

    static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*));
  };

  // For when TBase or TDerived is a fundamental type.
  template<typename TBase, typename TDerived>
  struct is_base_of<TBase, TDerived, true>
  {
    static const bool value = false;
  };

#if ETL_CPP17_SUPPORTED
  template <typename T1, typename T2>
  inline constexpr bool is_base_of_v = is_base_of<T1, T2>::value;
#endif

  //***************************************************************************
  /// is_class
  namespace private_type_traits
  {
    template <typename T> char test(int T::*); // Match for classes.

    struct dummy { char c[2]; };
    template <typename T> dummy test(...);     // Match for non-classes.
  }

  template <typename T>
  struct is_class : etl::integral_constant<bool, sizeof(private_type_traits::test<T>(0)) == 1U> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_class_v = is_class<T>::value;
#endif

  //***************************************************************************
  /// add_lvalue_reference
  template <typename T> struct add_lvalue_reference { typedef T& type; };
  template <typename T> struct add_lvalue_reference<T&> { typedef T& type; };
  template <>           struct add_lvalue_reference<void> { typedef void type; };
  template <>           struct add_lvalue_reference<const void> { typedef const void type; };
  template <>           struct add_lvalue_reference<volatile void> { typedef volatile void type; };
  template <>           struct add_lvalue_reference<const volatile void> { typedef const volatile void type; };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_lvalue_reference_t = typename etl::add_lvalue_reference<T>::type;
#endif

  //***************************************************************************
  /// add_rvalue_reference
#if ETL_CPP11_SUPPORTED
  template <typename T> struct add_rvalue_reference { using type = T && ; };
  template <typename T> struct add_rvalue_reference<T&> { using type = T & ; };
  template <>           struct add_rvalue_reference<void> { using type = void; };
  template <>           struct add_rvalue_reference<const void> { using type = const void; };
  template <>           struct add_rvalue_reference<volatile void> { using type = volatile void; };
  template <>           struct add_rvalue_reference<const volatile void> { using type = const volatile void; };
#endif

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_rvalue_reference_t = typename etl::add_rvalue_reference<T>::type;
#endif

  //***************************************************************************
  /// decval
#if ETL_CPP11_SUPPORTED
  template <typename T>
  typename etl::add_rvalue_reference<T>::type declval() ETL_NOEXCEPT;
#endif

  //***************************************************************************
  /// is_convertible
#if ETL_CPP11_SUPPORTED
  namespace private_type_traits
  {
    template <typename>
    using true_type_for = etl::true_type;

    template <typename T>
    auto returnable(int)->true_type_for<T()>;

    template <typename>
    auto returnable(...)->etl::false_type;

    template <typename TFrom, typename TTo>
    auto nonvoid_convertible(int)->true_type_for<decltype(etl::declval<void(&)(TTo)>()(etl::declval<TFrom>()))
    >;
    template <typename, typename>
    auto nonvoid_convertible(...)->etl::false_type;
  }

#if defined(ETL_COMPILER_ARM5)
  template <typename TFrom, typename TTo>
  struct is_convertible : etl::integral_constant<bool, __is_convertible_to(TFrom, TTo)> {};
#else
  template <typename TFrom, typename TTo>
  struct is_convertible : etl::integral_constant<bool, (decltype(private_type_traits::returnable<TTo>(0))::value &&
                                                        decltype(private_type_traits::nonvoid_convertible<TFrom, TTo>(0))::value) ||
                                                        (etl::is_void<TFrom>::value && etl::is_void<TTo>::value)> {};
#endif
#endif

#if ETL_CPP17_SUPPORTED
  template <typename TFrom, typename TTo >
  inline constexpr bool is_convertible_v = etl::is_convertible<TFrom, TTo>::value;
#endif

  //***************************************************************************
  /// Alignment templates.
  /// These require compiler specific intrinsics.
#if ETL_CPP11_SUPPORTED && !defined(ETL_COMPILER_ARM5)
  template <typename T> struct alignment_of : integral_constant<size_t, alignof(T)> { };
#elif defined(ETL_COMPILER_MICROSOFT)
  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof(T))> {};
#elif defined(ETL_COMPILER_IAR) || defined(ETL_COMPILER_TI)
  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {};
#else
  template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {};
#endif

  /// Specialisation of 'alignment_of' for 'void'.
  ///\ingroup type_traits
  template <> struct alignment_of<void> : integral_constant <size_t, 0> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr size_t alignment_of_v = etl::alignment_of<T>::value;
#endif

#else // Condition = ETL_USING_STL && ETL_CPP11_SUPPORTED

  //*****************************************************************************
  // Traits are derived from the STL
  //*****************************************************************************

  //***************************************************************************
  /// integral_constant
  ///\ingroup type_traits
  template <typename T, const T VALUE>
  struct integral_constant : std::integral_constant<T, VALUE> {};

  /// integral_constant specialisations
  ///\ingroup type_traits
  typedef integral_constant<bool, false> false_type;
  typedef integral_constant<bool, true>  true_type;

#if ETL_CPP17_SUPPORTED
  template <bool B>
  using bool_constant = std::bool_constant<B>;
#else
  template <bool B>
  struct bool_constant : std::integral_constant<bool, B> { };
#endif

  //***************************************************************************
  /// negation
  ///\ingroup type_traits
#if ETL_CPP17_SUPPORTED
  template <typename T>
  struct negation : std::negation<T>
  {
  };

  template <typename T>
  inline constexpr bool negation_v = std::negation_v<T>;
#endif

  //***************************************************************************
  /// remove_reference
  ///\ingroup type_traits
  template <typename T> struct remove_reference : std::remove_reference<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_reference_t = std::remove_reference_t<T>;
#endif

  //***************************************************************************
  /// remove_pointer
  ///\ingroup type_traits
  template <typename T> struct remove_pointer : std::remove_pointer<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_pointer_t = std::remove_pointer_t<T>;
#endif

  //***************************************************************************
  /// add_pointer
  ///\ingroup type_traits
  template <typename T> struct add_pointer : std::add_pointer<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_pointer_t = std::add_pointer_t<T>;
#endif

  //***************************************************************************
  /// is_const
  ///\ingroup type_traits
  template <typename T> struct is_const : std::is_const<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_const_v = std::is_const_v<T>;
#endif

  //***************************************************************************
  /// remove_const
  ///\ingroup type_traits
  template <typename T> struct remove_const : std::remove_const<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_const_t = std::remove_const_t<T>;
#endif

  //***************************************************************************
  /// add_const
  ///\ingroup type_traits
  template <typename T> struct add_const : std::add_const<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_const_t = std::add_const_t<T>;
#endif

  //***************************************************************************
  /// is_volatile
  ///\ingroup type_traits
  template <typename T> struct is_volatile : std::is_volatile<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_volatile_v = std::is_volatile_v<T>;
#endif

  //***************************************************************************
  /// remove_volatile
  ///\ingroup type_traits
  template <typename T> struct remove_volatile : std::remove_volatile<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_volatile_t = std::remove_volatile_t<T>;
#endif

  //***************************************************************************
  /// add_volatile
  ///\ingroup type_traits
  template <typename T> struct add_volatile : std::add_volatile<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_volatile_t = std::add_volatile_t<T>;
#endif

  //***************************************************************************
  /// remove_cv
  ///\ingroup type_traits
  template <typename T> struct remove_cv : std::remove_cv<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_cv_t = std::remove_cv_t<T>;
#endif

  //***************************************************************************
  /// add_cv
  ///\ingroup type_traits
  template <typename T> struct add_cv : std::add_cv<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_cv_t = std::add_cv_t<T>;
#endif

  //***************************************************************************
  /// is_integral
  ///\ingroup type_traits
  template <typename T> struct is_integral : std::is_integral<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_integral_v = std::is_integral_v<T>;
#endif

  //***************************************************************************
  /// is_signed
  ///\ingroup type_traits
  template <typename T> struct is_signed : std::is_signed<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_signed_v = std::is_signed_v<T>;
#endif

  //***************************************************************************
  /// is_unsigned
  ///\ingroup type_traits
  template <typename T> struct is_unsigned : std::is_unsigned<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_unsigned_v = std::is_unsigned_v<T>;
#endif

  //***************************************************************************
  /// is_floating_point
  ///\ingroup type_traits
  template <typename T> struct is_floating_point : std::is_floating_point<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_floating_point_v = std::is_floating_point_v<T>;
#endif

  //***************************************************************************
  /// is_same
  ///\ingroup type_traits
  template <typename T1, typename T2> struct is_same : std::is_same<T1, T2> {};

#if ETL_CPP17_SUPPORTED
  template <typename T1, typename T2>
  inline constexpr bool is_same_v = std::is_same_v<T1, T2>;
#endif

  //***************************************************************************
  /// is_void
  ///\ingroup type_traits
  template<typename T> struct is_void : std::is_void<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_void_v = std::is_void_v<T>;
#endif

  //***************************************************************************
  /// is_arithmetic
  ///\ingroup type_traits
  template<typename T> struct is_arithmetic : std::is_arithmetic<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_arithmetic_v = std::is_arithmetic_v<T>;
#endif

  //***************************************************************************
  /// is_fundamental
  ///\ingroup type_traits
  template <typename T> struct is_fundamental : std::is_fundamental<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_fundamental_v = std::is_fundamental_v<T>;
#endif

  //***************************************************************************
  /// is_compound
  ///\ingroup type_traits
  template <typename T> struct is_compound : std::is_compound<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_compound_v = std::is_compound_v<T>;
#endif

  //***************************************************************************
  /// is_array
  ///\ingroup type_traits
  template <typename T> struct is_array : std::is_array<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_array_v = std::is_array_v<T>;
#endif

  //***************************************************************************
  /// is_pointer
  ///\ingroup type_traits
  template<typename T> struct is_pointer : std::is_pointer<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_pointer_v = std::is_pointer_v<T>;
#endif

  //***************************************************************************
  /// is_reference
  ///\ingroup type_traits
  template<typename T> struct is_reference : std::is_reference<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_reference_v = std::is_reference_v<T>;
#endif

  //***************************************************************************
  /// is_lvalue_reference
  ///\ingroup type_traits
  template<typename T> struct is_lvalue_reference : std::is_lvalue_reference<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_lvalue_reference_v = std::is_lvalue_reference_v<T>;
#endif

  //***************************************************************************
  /// is_rvalue_reference
  ///\ingroup type_traits
#if ETL_CPP11_SUPPORTED
  template<typename T> struct is_rvalue_reference : std::is_rvalue_reference<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_rvalue_reference_v = std::is_rvalue_reference_v<T>;
#endif
#endif

  //***************************************************************************
  /// is_pod
  ///\ingroup type_traits
  template <typename T>
  struct is_pod : std::integral_constant<bool, std::is_standard_layout<T>::value && std::is_trivial<T>::value> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_pod_v = std::is_standard_layout_v<T> && std::is_trivial_v<T>;
#endif

#if defined(ETL_COMPILER_GCC)
  #if ETL_COMPILER_VERSION >= 5
    #define ETL_GCC_V5_TYPE_TRAITS_SUPPORTED
  #endif
#endif

#if !defined(ARDUINO) && ETL_NOT_USING_STLPORT && defined(ETL_GCC_V5_TYPE_TRAITS_SUPPORTED)
  //***************************************************************************
  /// is_trivially_constructible
  ///\ingroup type_traits
  template <typename T> struct is_trivially_constructible : std::is_trivially_constructible<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_constructible_v = std::is_trivially_constructible_v<T>;
#endif

  //***************************************************************************
  /// is_trivially_copy_constructible
  ///\ingroup type_traits
  template <typename T> struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_copy_constructible_v = std::is_trivially_copy_constructible_v<T>;
#endif

  //***************************************************************************
  /// is_trivially_destructible
  ///\ingroup type_traits
  template <typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_destructible_v = std::is_trivially_destructible_v<T>;
#endif

  //***************************************************************************
  /// is_trivially_copy_assignable
  ///\ingroup type_traits
  template <typename T> struct is_trivially_copy_assignable : std::is_trivially_copy_assignable<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_copy_assignable_v = std::is_trivially_copy_assignable_v<T>;
#endif

  //***************************************************************************
  /// is_trivially_copyable
  ///\ingroup type_traits
  template <typename T> struct is_trivially_copyable : std::is_trivially_copyable<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_trivially_copyable_v = std::is_trivially_copyable_v<T>;
#endif
#else
    //***************************************************************************
    /// is_trivially_constructible
    ///\ingroup type_traits
    template <typename T> struct is_trivially_constructible : std::is_pod<T> {};

  #if ETL_CPP17_SUPPORTED
    template <typename T>
    inline constexpr bool is_trivially_constructible_v = std::is_pod_v<T>;
  #endif

    //***************************************************************************
    /// is_trivially_copy_constructible
    ///\ingroup type_traits
    template <typename T> struct is_trivially_copy_constructible : std::is_pod<T> {};

  #if ETL_CPP17_SUPPORTED
    template <typename T>
    inline constexpr bool is_trivially_copy_constructible_v = std::is_pod_v<T>;
  #endif

    //***************************************************************************
    /// is_trivially_destructible
    ///\ingroup type_traits
    template <typename T> struct is_trivially_destructible : std::is_pod<T> {};

  #if ETL_CPP17_SUPPORTED
    template <typename T>
    inline constexpr bool is_trivially_destructible_v = std::is_pod_v<T>;
  #endif

    //***************************************************************************
    /// is_trivially_copy_assignable
    ///\ingroup type_traits
    template <typename T> struct is_trivially_copy_assignable : std::is_pod<T> {};

  #if ETL_CPP17_SUPPORTED
    template <typename T>
    inline constexpr bool is_trivially_copy_assignable_v = std::is_pod_v<T>;
  #endif

    //***************************************************************************
    /// is_trivially_copyable
    ///\ingroup type_traits
    template <typename T> struct is_trivially_copyable : std::is_pod<T> {};

  #if ETL_CPP17_SUPPORTED
    template <typename T>
    inline constexpr bool is_trivially_copyable_v = std::is_pod_v<T>;
  #endif
#endif

  //***************************************************************************
  /// conditional
  ///\ingroup type_traits
  template <bool B, typename T, typename F>  struct conditional { typedef T type; };
  template <typename T, typename F> struct conditional<false, T, F> { typedef F type; };

  //***************************************************************************
  /// make_signed
  ///\ingroup type_traits
  template <typename T> struct make_signed : std::make_signed<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using make_signed_t = std::make_signed_t<T>;
#endif

  //***************************************************************************
  /// make_unsigned
  ///\ingroup type_traits
  template <typename T> struct make_unsigned : std::make_unsigned<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using make_unsigned_t = std::make_unsigned_t<T>;
#endif

  //***************************************************************************
  /// enable_if
  ///\ingroup type_traits
  template <bool B, typename T = void> struct enable_if : std::enable_if<B, T> {};

#if ETL_CPP14_SUPPORTED
  template <bool B, typename T = void>
  using enable_if_t = std::enable_if_t<B, T>;
#endif

  //***************************************************************************
  /// extent
  ///\ingroup type_traits
  template <typename T, size_t MAXN = 0U>
  struct extent : std::extent<T, MAXN> {};

#if ETL_CPP17_SUPPORTED
  template <typename T, size_t MAXN = 0U>
  inline constexpr size_t extent_v = std::extent_v<T, MAXN>;
#endif

  //***************************************************************************
  /// remove_extent
  ///\ingroup type_traits
  template <typename T> struct remove_extent : std::remove_extent<T> { };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_extent_t = std::remove_extent_t<T>;
#endif

  //***************************************************************************
  /// remove_all_extents
  ///\ingroup type_traits
  template <typename T> struct remove_all_extents : std::remove_all_extents<T> { };

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using remove_all_extents_t = std::remove_all_extents_t<T>;
#endif

  //***************************************************************************
  /// rank
  ///\ingroup type_traits
  template <typename T>struct rank : std::rank<T> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr size_t rank_v = std::rank_v<T>;
#endif

  //***************************************************************************
  /// decay
  ///\ingroup type_traits
  template <typename T> struct decay : std::decay<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using decay_t = std::decay_t<T>;
#endif

  //***************************************************************************
  /// is_base_of
  ///\ingroup type_traits
  template<typename TBase, typename TDerived> struct is_base_of : std::is_base_of<TBase, TDerived> {};

#if ETL_CPP17_SUPPORTED
  template <typename TBase, typename TDerived>
  inline constexpr bool is_base_of_v = std::is_base_of_v<TBase, TDerived>;
#endif

  //***************************************************************************
  /// is_class
  template <typename T> struct is_class : std::is_class<T>{};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr bool is_class_v = is_class<T>::value;
#endif

  //***************************************************************************
  /// add_lvalue_reference
  template <typename T> struct add_lvalue_reference : std::add_lvalue_reference<T> {};

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_lvalue_reference_t = std::add_lvalue_reference_t<T>;
#endif

  //***************************************************************************
  /// add_rvalue_reference
#if ETL_CPP11_SUPPORTED
  template <typename T> struct add_rvalue_reference : std::add_rvalue_reference<T> {};
#endif

#if ETL_CPP14_SUPPORTED
  template <typename T>
  using add_rvalue_reference_t = std::add_rvalue_reference_t<T>;
#endif

  //***************************************************************************
  /// decval
#if ETL_CPP11_SUPPORTED
  template <typename T>
  typename std::add_rvalue_reference<T>::type declval() ETL_NOEXCEPT;
#endif

  //***************************************************************************
  /// is_convertible
  ///\ingroup type_traits
#if ETL_CPP11_SUPPORTED
  template <typename TFrom, typename TTo>
  struct is_convertible : std::is_convertible<TFrom, TTo> {};
#endif

#if ETL_CPP17_SUPPORTED
  template <typename TFrom, typename TTo>
  inline constexpr bool is_convertible_v = std::is_convertible_v<TFrom, TTo>;
#endif

  //***************************************************************************
  /// Alignment templates.
  ///\ingroup type_traits
  template <typename T> struct alignment_of : std::alignment_of<T> {};
  template <> struct alignment_of<void> : std::integral_constant<size_t, 0> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr size_t alignment_of_v = std::alignment_of_v<T>;
#endif

#endif // Condition = ETL_USING_STL && ETL_CPP11_SUPPORTED

  //***************************************************************************
  // ETL extended type traits.
  //***************************************************************************

  //***************************************************************************
  /// conditional_integral_constant
  // /\ingroup type_traits
  template <bool B, typename T, T TRUE_VALUE, T FALSE_VALUE>
  struct conditional_integral_constant;

  template <typename T, T TRUE_VALUE, T FALSE_VALUE>
  struct conditional_integral_constant<true, T, TRUE_VALUE, FALSE_VALUE>
  {
    ETL_STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
    static const T value = TRUE_VALUE;
  };

  template <typename T, T TRUE_VALUE, T FALSE_VALUE>
  struct conditional_integral_constant<false, T, TRUE_VALUE, FALSE_VALUE>
  {
    ETL_STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type");
    static const T value = FALSE_VALUE;
  };


#if ETL_CPP11_SUPPORTED
  //***************************************************************************
  /// Template to determine if a type is one of a specified list.
  ///\ingroup types
  template <typename T, typename T1, typename... TRest>
  struct is_one_of
  {
    static const bool value = etl::is_same<T, T1>::value ||
                              etl::is_one_of<T, TRest...>::value;
  };

  template <typename T, typename T1>
  struct is_one_of<T, T1>
  {
    static const bool value = etl::is_same<T, T1>::value;
  };
#else
  //***************************************************************************
  /// Template to determine if a type is one of a specified list.
  ///\ingroup types
  template <typename T,
            typename T1, typename T2 = void, typename T3 = void, typename T4 = void, 
            typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, 
            typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, 
            typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
  struct is_one_of
  {
    static const bool value = 
        etl::is_same<T, T1>::value ||
        etl::is_same<T, T2>::value ||
        etl::is_same<T, T3>::value ||
        etl::is_same<T, T4>::value ||
        etl::is_same<T, T5>::value ||
        etl::is_same<T, T6>::value ||
        etl::is_same<T, T7>::value ||
        etl::is_same<T, T8>::value ||
        etl::is_same<T, T9>::value ||
        etl::is_same<T, T10>::value ||
        etl::is_same<T, T11>::value ||
        etl::is_same<T, T12>::value ||
        etl::is_same<T, T13>::value ||
        etl::is_same<T, T14>::value ||
        etl::is_same<T, T15>::value ||
        etl::is_same<T, T16>::value;
  };
#endif

#if ETL_CPP17_SUPPORTED
  template <typename T, typename... TRest>
  inline constexpr bool is_one_of_v = etl::is_one_of<T, TRest...>::value;
#endif

  //***************************************************************************
  /// A set of templates to allow related types to be derived.
  ///\ingroup types

  // Default.
  template <typename T>
  struct types
  {
  private:

    typedef typename etl::remove_reference<typename etl::remove_cv<T>::type>::type type_t;

  public:

    typedef type_t              type;
    typedef type_t&             reference;
    typedef const type_t&       const_reference;
    typedef type_t*             pointer;
    typedef const type_t*       const_pointer;
    typedef const type_t* const const_pointer_const;

#if ETL_CPP11_SUPPORTED
    typedef type_t&&            rvalue_reference;
#endif
  };

  // Pointers.
  template <typename T>
  struct types<T*>
  {
  private:

    typedef typename etl::remove_reference<typename etl::remove_cv<T>::type>::type type_t;

  public:

    typedef type_t              type;
    typedef type_t&             reference;
    typedef const type_t&       const_reference;
    typedef type_t*             pointer;
    typedef const type_t*       const_pointer;
    typedef const type_t* const const_pointer_const;

#if ETL_CPP11_SUPPORTED
    typedef type_t&&            rvalue_reference;
#endif
  };

  // Pointers.
  template <typename T>
  struct types<T* const>
  {
  private:

    typedef typename etl::remove_reference<typename etl::remove_cv<T>::type>::type type_t;

  public:

    typedef type_t              type;
    typedef type_t&             reference;
    typedef const type_t&       const_reference;
    typedef type_t*             pointer;
    typedef const type_t* const_pointer;
    typedef const type_t* const const_pointer_const;

#if ETL_CPP11_SUPPORTED
    typedef type_t&&            rvalue_reference;
#endif
  };

  // References.
  template <typename T>
  struct types<T&>
  {
  private:

    typedef typename etl::remove_reference<typename etl::remove_cv<T>::type>::type type_t;

  public:

    typedef type_t              type;
    typedef type_t&             reference;
    typedef const type_t&       const_reference;
    typedef type_t*             pointer;
    typedef const type_t*       const_pointer;
    typedef const type_t* const const_pointer_const;

#if ETL_CPP11_SUPPORTED
    typedef type_t&&            rvalue_reference;
#endif
  };

#if ETL_CPP11_SUPPORTED
  // rvalue References.
  template <typename T>
  struct types<T&&>
  {
  private:

    typedef typename etl::remove_reference<typename etl::remove_cv<T>::type>::type type_t;

  public:

    typedef type_t              type;
    typedef type_t&             reference;
    typedef const type_t&       const_reference;
    typedef type_t*             pointer;
    typedef const type_t*       const_pointer;
    typedef const type_t* const const_pointer_const;

#if ETL_CPP11_SUPPORTED
    typedef type_t&&            rvalue_reference;
#endif
  };
#endif

#if ETL_CPP11_SUPPORTED
  template <typename T>
  using types_t = typename types<T>::type;

  template <typename T>
  using types_r = typename types<T>::reference;

  template <typename T>
  using types_cr = typename types<T>::const_reference;

  template <typename T>
  using types_rr = typename types<T>::rvalue_reference;

  template <typename T>
  using types_p = typename types<T>::pointer;

  template <typename T>
  using types_cp = typename types<T>::const_pointer;

  template <typename T>
  using types_cpc = typename types<T>::const_pointer_const;
#endif

  //***************************************************************************
  /// size_of
  ///\ingroup types
  template <typename T> struct size_of : etl::integral_constant<size_t, sizeof(T)> {};
  template <> struct size_of<void> : etl::integral_constant<size_t, 1U> {};

#if ETL_CPP17_SUPPORTED
  template <typename T>
  inline constexpr size_t size_of_v = etl::size_of<T>::value;
#endif

#if ETL_CPP11_SUPPORTED
  //***************************************************************************
  /// are_all_same
  template <typename T, typename T1, typename... TRest>
  struct are_all_same
  {
    static const bool value = etl::is_same<T, T1>::value &&
      etl::are_all_same<T, TRest...>::value;
  };

  template <typename T, typename T1>
  struct are_all_same<T, T1>
  {
    static const bool value = etl::is_same<T, T1>::value;
  };
#endif

#if ETL_CPP17_SUPPORTED
  template <typename T, typename T1, typename... TRest>
  inline constexpr bool are_all_same_v = are_all_same<T, T1, TRest...>::value;
#endif
}

#endif // ETL_TYPE_TRAITS_INCLUDED
