/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2013/12/09
/// 
/// @brief  タイプチェックテンプレートクラス。
/// 
/// ****************************************************************************

#pragma once

#include "CPL_Core_Define.h"

namespace CPL {

template<class T> using tv_is_void                    = typename std::is_void                   <T>::value;
template<class T> using tv_is_integral                = typename std::is_integral               <T>::value;
template<class T> using tv_is_floating_point          = typename std::is_floating_point         <T>::value;
template<class T> using tv_is_array                   = typename std::is_array                  <T>::value;
template<class T> using tv_is_pointer                 = typename std::is_pointer                <T>::value;
template<class T> using tv_is_lvalue_reference        = typename std::is_lvalue_reference       <T>::value;
template<class T> using tv_is_rvalue_reference        = typename std::is_rvalue_reference       <T>::value;
template<class T> using tv_is_member_object_pointer   = typename std::is_member_object_pointer  <T>::value;
template<class T> using tv_is_member_function_pointer = typename std::is_member_function_pointer<T>::value;
template<class T> using tv_is_enum                    = typename std::is_enum                   <T>::value;
template<class T> using tv_is_union                   = typename std::is_union                 <T>::value;
template<class T> using tv_is_class                   = typename std::is_class                 <T>::value;
template<class T> using tv_is_function                = typename std::is_function               <T>::value;

template<class T> using tv_is_reference      = typename std::is_reference     <T>::value;
template<class T> using tv_is_arithmetic     = typename std::is_arithmetic    <T>::value;
template<class T> using tv_is_fundamental    = typename std::is_fundamental   <T>::value;
template<class T> using tv_is_object         = typename std::is_object        <T>::value;
template<class T> using tv_is_scalar         = typename std::is_scalar        <T>::value;
template<class T> using tv_is_compound       = typename std::is_compound      <T>::value;
template<class T> using tv_is_member_pointer = typename std::is_member_pointer<T>::value;

template<class T> using tv_is_const                           = typename std::is_const                          <T>::value;
template<class T> using tv_is_volatile                        = typename std::is_volatile                       <T>::value;
template<class T> using tv_is_trivial                         = typename std::is_trivial                        <T>::value;
template<class T> using tv_is_trivially_copyable              = typename std::is_trivially_copyable             <T>::value;
template<class T> using tv_is_standard_layout                 = typename std::is_standard_layout                <T>::value;
template<class T> using tv_is_pod                             = typename std::is_pod                            <T>::value;
template<class T> using tv_is_literal_type                    = typename std::is_literal_type                   <T>::value;
template<class T> using tv_is_empty                           = typename std::is_empty                          <T>::value;
template<class T> using tv_is_polymorphic                     = typename std::is_polymorphic                    <T>::value;
template<class T> using tv_is_abstract                        = typename std::is_abstract                       <T>::value;
template<class T> using tv_is_signed                          = typename std::is_signed                         <T>::value;
template<class T> using tv_is_unsigned                        = typename std::is_unsigned                       <T>::value;
template<class T> using tv_is_constructible                   = typename std::is_constructible                  <T>::value;
template<class T> using tv_is_default_constructible           = typename std::is_default_constructible          <T>::value;
template<class T> using tv_is_copy_constructible              = typename std::is_copy_constructible             <T>::value;
template<class T> using tv_is_move_constructible              = typename std::is_move_constructible             <T>::value;
template<class T,class U>
                  using tv_is_assignable                      = typename std::is_assignable                     <T,U>::value;
template<class T> using tv_is_copy_assignable                 = typename std::is_copy_assignable                <T>::value;
template<class T> using tv_is_move_assignable                 = typename std::is_move_assignable                <T>::value;
template<class T> using tv_is_destructible                    = typename std::is_destructible                   <T>::value;
template<class T> using tv_is_trivially_constructible         = typename std::is_trivially_constructible        <T>::value;
template<class T> using tv_is_trivially_default_constructible = typename std::is_trivially_default_constructible<T>::value;
template<class T> using tv_is_trivially_copy_constructible    = typename std::is_trivially_copy_constructible   <T>::value;
template<class T> using tv_is_trivially_move_constructible    = typename std::is_trivially_move_constructible   <T>::value;
template<class T, class U>
                  using tv_is_trivially_assignable            = typename std::is_trivially_assignable           <T,U>::value;
template<class T> using tv_is_trivially_copy_assignable       = typename std::is_trivially_copy_assignable      <T>::value;
template<class T> using tv_is_trivially_move_assignable       = typename std::is_trivially_move_assignable      <T>::value;
template<class T> using tv_is_trivially_destructible          = typename std::is_trivially_destructible         <T>::value;
template<class T> using tv_is_nothrow_constructible           = typename std::is_nothrow_constructible          <T>::value;
template<class T> using tv_is_nothrow_default_constructible   = typename std::is_nothrow_default_constructible  <T>::value;
template<class T> using tv_is_nothrow_copy_constructible      = typename std::is_nothrow_copy_constructible     <T>::value;
template<class T> using tv_is_nothrow_move_constructible      = typename std::is_nothrow_move_constructible     <T>::value;
template<class T, class U>
                  using tv_is_nothrow_assignable              = typename std::is_nothrow_assignable             <T,U>::value;
template<class T> using tv_is_nothrow_copy_assignable         = typename std::is_nothrow_copy_assignable        <T>::value;
template<class T> using tv_is_nothrow_move_assignable         = typename std::is_nothrow_move_assignable        <T>::value;
template<class T> using tv_is_nothrow_destructible            = typename std::is_nothrow_destructible           <T>::value;
template<class T> using tv_has_virtual_destructor             = typename std::has_virtual_destructor            <T>::value;

template<class T> using tv_alignment_of = typename std::alignment_of <T>::value;
template<class T> using tv_rank         = typename std::rank         <T>::value;
template<class T> using tv_extent       = typename std::extent       <T>::value;

template<class T, class U> using tv_is_same        = typename std::is_same       <T,U>::value;
template<class B, class D> using tv_is_base_of     = typename std::is_base_of    <B,D>::value;
template<class F, class T> using tv_is_convertible = typename std::is_convertible<F,T>::value;

template<class T> using tt_remove_const    = typename std::remove_const   <T>::type;
template<class T> using tt_remove_volatile = typename std::remove_volatile<T>::type;
template<class T> using tt_remove_cv       = typename std::remove_cv      <T>::type;
template<class T> using tt_add_const       = typename std::add_const      <T>::type;
template<class T> using tt_add_volatile    = typename std::add_volatile   <T>::type;
template<class T> using tt_add_cv          = typename std::add_cv         <T>::type;

template<class T> using tt_remove_reference     = typename std::remove_reference    <T>::type;
template<class T> using tt_add_lvalue_reference = typename std::add_lvalue_reference<T>::type;
template<class T> using tt_add_rvalue_reference = typename std::add_rvalue_reference<T>::type;

template<class T> using tt_make_signed   = typename std::make_signed  <T>::type;
template<class T> using tt_make_unsigned = typename std::make_unsigned<T>::type;

template<class T> using tt_remove_extent      = typename std::remove_extent     <T>::type;
template<class T> using tt_remove_all_extents = typename std::remove_all_extents<T>::type;

template<class T> using tt_add_pointer    = typename std::add_pointer   <T>::type;
template<class T> using tt_remove_pointer = typename std::remove_pointer<T>::type;

template<class T> using tt_decay           = typename std::decay          <T>::type;
template<bool C, class T = void>
                  using tt_enable_if       = typename std::enable_if      <C,T>::type;
template<bool B, class T, class F>
                  using tt_conditional     = typename std::conditional    <B,T,F>::type;
template<class... T_Params>
                  using tt_common_type     = typename std::common_type    <T_Params...>::type;
template<class T> using tt_underlying_type = typename std::underlying_type<T>::type;
template<class F> using tt_result_of       = typename std::result_of      <F>::type;



// _____________________________________________________________________________
/// @brief 型属性クラス…改め、名前空間（Clangというか標準対応のため）
///
// *****************************************************************************
// class Traits
namespace Traits
{
//private:
  template<class T> struct zzc_type_ { using type = T; };
  template<int N> struct zzc_num_
  {
    static constexpr int  num   = N;
    static constexpr bool value = N != 0;
  };
  struct zzc_false_ : zzc_num_<0> {};
  struct zzc_true_  : zzc_num_<1> {};
  
  // bool
  template<bool f> struct zzc_bool_        : zzc_true_ {};
  template<>       struct zzc_bool_<false> : zzc_false_ {};

//public:
  // _____________________________________________________________________________
  /// @brief 複数の指定された型が全て同じかどうかチェック。
  /// ※ std::is_sameがあるので非推奨。
  /// 
  /// @par Example 
  /// auto flag = IsSame<A,B,C>::value; // A,B,Cは何らかのクラス。flag==falseとなる。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class... T_Params> struct IsSame : zzc_false_ {};
  /// @cond
  template<class T>
  struct IsSame<T, T> : zzc_true_{};
  
  template<class T, class... T_Params>
  struct IsSame<T, T, T_Params...> : IsSame<T, T_Params...>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 複数の指定された型が全て同じかどうかチェック（template版）
  /// 
  /// @par Example 
  /// template<class> class X{};\n
  /// template<class> class Y{};\n
  /// auto flag0 = IsSameT< X, X >::value; // flag0 == true\n
  /// auto flag1 = IsSameT< X, Y >::value; // flag1 == false
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class... T_Params> struct IsSameT : zzc_false_ {};
  /// @cond
  template<template<class... U> class T>
  struct IsSameT<T<>, T<>> : zzc_true_{};
  
  template<template<class... U>class T, class... T_Params>
  struct IsSameT<T<>, T<>, T_Params...> : IsSame<T<>, T_Params...>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 複数の型に指定型がいくつ含まれるかチェック。
  /// 
  /// numに一致数、valueに１つ以上の型が一致したかどうかが設定される。\n
  /// TupleType<>の中身は展開される。
  /// @tparam T_Check     : 比較する型。
  /// @tparam T_Params... : 比較される型を続けて指定する。
  /// @par Example 
  /// bool f = IsCompare<int, char,short,int,int>::value; // f = 1;\n
  /// int  n = IsCompare<int, float,int,double,int,int>::num; // n = 3;
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_Check, class... T_Params>
  struct IsCompare
  {
  private:
    /// @cond
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    template<int N, class T_Check, class T0, class... T_Params>
    struct zzz_counter_
      : zzz_counter_< N + IsSame<T_Check,T0>::value, T_Check, T_Params... >
    {};
    //
    template<int N, class T_Check, class T0>
    struct zzz_counter_<N,T_Check,T0>
      : zzc_num_< N + IsSame<T_Check,T0>::value >
    {};
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    template<int N, class T_Check, class...X, class... T_Params>
    struct zzz_counter_<N, T_Check, TupleType<X...>, T_Params...>
      : zzz_counter_< N + IsCompare<T_Check,X...>::value, T_Check, T_Params... >
    {};
    //
    template<int N, class T_Check, class...X>
    struct zzz_counter_<N, T_Check, TupleType<X...>>
      : zzc_num_< N + IsCompare<T_Check,X...>::value >
    {};
    /// @endcond
  public:
    static const bool value = zzz_counter_<0,T_Check,T_Params...>::value;
    static const int  num   = zzz_counter_<0,T_Check,T_Params...>::num;
  };

  // _____________________________________________________________________________
  /// @brief 型の条件２分岐。
  /// @tparam f       : 論理フラグ。
  /// @tparam T_true  : f == trueの場合の型。
  /// @tparam T_false : f == falseの場合の型。
  /// @par Example
  /// IfType<f,T,U>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<bool f, class T_true, class T_false>
  struct IfType : zzc_type_<T_true> {};
  /// @cond
  template<class T_true, class T_false>
  struct IfType<false, T_true, T_false> : zzc_type_<T_false> {};
  /// @endcond


  // _____________________________________________________________________________
  /// @brief 型の条件２分岐数値型。
  /// @tparam f       : 論理フラグ。
  /// @tparam T_true  : f == trueの場合の数値。
  /// @tparam T_false : f == falseの場合の数値。
  /// @par Example
  /// IfTypeN<f,T,U>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<int f, int N_true, int N_false>
  struct IfTypeN : zzc_num_<N_true> {};
  /// @cond
  template<int N_true, int N_false>
  struct IfTypeN<0, N_true, N_false> : zzc_num_<N_false> {};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 型の同一条件による２分岐。
  /// @tparam T0      : 比較型１
  /// @tparam T1      : 比較型２
  /// @tparam T_true  : T0 == T1の場合の型。
  /// @tparam T_false : T0 != T1の場合の型。
  /// @par Example
  /// IfSameType<T0,T1,T_true,T_false>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T0, class T1, class T_true, class T_false = T0>
  struct IfSameType : IfType< IsSame<T0,T1>::value, T_true, T_false> {};

  // _____________________________________________________________________________
  /// @brief 型の同一条件による数値２分岐。
  /// @tparam T0      : 比較型１
  /// @tparam T1      : 比較型２
  /// @tparam T_true  : T0 == T1の場合の数値。
  /// @tparam T_false : T0 != T1の場合の数値。
  /// @par Example
  /// IfSameType<T0,T1,T_true,T_false>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T0, class T1, int N_true, int N_false>
  struct IfSameTypeN : IfTypeN< IsSame<T0,T1>::value, N_true, N_false> {};

  // _____________________________________________________________________________
  /// @brief 型のDefault_クラス条件による２分岐。
  /// @tparam T0      : 比較する型。
  /// @tparam T_true  : T0 == Default_の場合の型。
  /// @tparam T_false : T0 != Default_の場合の型。
  /// @par Example
  /// IfDefaultType<T0,T_true,T_false>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T0, class T_true, class T_false = T0>
  struct IfDefaultType : IfSameType< T0, Default_, T_true, T_false> {};

  // _____________________________________________________________________________
  /// @brief const修飾。
  /// @tparam T : const修飾する型。
  /// @par Example
  /// AddConst<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AddConst : zzc_type_<T const>{};

  // _____________________________________________________________________________
  /// @brief const外し。
  /// @tparam T : constを外す型。
  /// @par Example
  /// RemoveConst<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct RemoveConst             : zzc_type_<T>{};
  /// @cond
  template<class T>       struct RemoveConst<T const>    : zzc_type_<T>{};
  template<class T>       struct RemoveConst<T const[]>  : zzc_type_<T[]>{};
  template<class T,int N> struct RemoveConst<T const[N]> : zzc_type_<T[N]>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief const改造？ ポインタ、参照等は参照先をconst化する。
  /// @tparam T : const改造する型。
  /// @par Example
  /// AlterConst<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct AlterConst          : zzc_type_<T const>{};
  /// @cond
  template<class T>       struct AlterConst<T const> : zzc_type_<T const>{};
  template<class T>       struct AlterConst<T*>      : zzc_type_<T const*>{};
  template<class T>       struct AlterConst<T&>      : zzc_type_<T const&>{};
  template<class T>       struct AlterConst<T[]>     : zzc_type_<T const[]>{};
  template<class T,int N> struct AlterConst<T[N]>    : zzc_type_<T const[N]>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 非const改造。ポインタ、参照等は参照先を非const化する。
  /// @tparam T : 非const改造する型。
  /// @par Example
  /// RefineConst<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct RefineConst             : zzc_type_<T>{};
  /// @cond
  template<class T>       struct RefineConst<T const>    : zzc_type_<T>{};
  template<class T>       struct RefineConst<T const*>   : zzc_type_<T*>{};
  template<class T>       struct RefineConst<T const&>   : zzc_type_<T&>{};
  template<class T>       struct RefineConst<T const[]>  : zzc_type_<T[]>{};
  template<class T,int N> struct RefineConst<T const[N]> : zzc_type_<T[N]>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief volatile修飾。
  /// @tparam T : volatile修飾する型。
  /// @par Example
  /// AddVolatile<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AddVolatile : zzc_type_<T volatile>{};

  // _____________________________________________________________________________
  /// @brief volatile外し。
  /// @tparam T : volatileを外す元の型。
  /// @par Example
  /// RemoveVolatile<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct RemoveVolatile                : zzc_type_<T>{};
  /// @cond
  template<class T>       struct RemoveVolatile<T volatile>    : zzc_type_<T>{};
  template<class T>       struct RemoveVolatile<T volatile[]>  : zzc_type_<T[]>{};
  template<class T,int N> struct RemoveVolatile<T volatile[N]> : zzc_type_<T[N]>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief volatile改造？ ポインタ、参照等は参照先をvolatile化する。
  /// @tparam T : volatile改造する型。
  /// @par Example
  /// AlterVolatile<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct AlterVolatile             : zzc_type_<T volatile>{};
  /// @cond
  template<class T>       struct AlterVolatile<T volatile> : zzc_type_<T volatile>{};
  template<class T>       struct AlterVolatile<T*>         : zzc_type_<T volatile*>{};
  template<class T>       struct AlterVolatile<T&>         : zzc_type_<T volatile&>{};
  template<class T>       struct AlterVolatile<T[]>        : zzc_type_<T volatile[]>{};
  template<class T,int N> struct AlterVolatile<T[N]>       : zzc_type_<T volatile[N]>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 非volatile改造。
  /// @tparam T : 非volatile改造する型。
  /// @par Example
  /// RefineVolatile<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct RefineVolatile                : zzc_type_<T>{};
  /// @cond
  template<class T>       struct RefineVolatile<T volatile>    : zzc_type_<T>{};
  template<class T>       struct RefineVolatile<T volatile*>   : zzc_type_<T*>{};
  template<class T>       struct RefineVolatile<T volatile&>   : zzc_type_<T&>{};
  template<class T>       struct RefineVolatile<T volatile[]>  : zzc_type_<T[]>{};
  template<class T,int N> struct RefineVolatile<T volatile[N]> : zzc_type_<T[N]>{};
  /// @endcond


  // _____________________________________________________________________________
  /// @brief const/volatile修飾。
  /// @tparam T : const/volatile修飾する型。
  /// @par Example
  /// AddCV<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AddCV
    : zzc_type_< typename AddConst< typename AddVolatile<T>::type >::type >{};

  // _____________________________________________________________________________
  /// @brief const/volatile外し。
  /// @tparam T : const/volatile修飾を外す元の型。
  /// @par Example
  /// UnCV<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct RemoveCV
    : zzc_type_<typename RemoveConst< typename RemoveVolatile<T>::type>::type >{};

  // _____________________________________________________________________________
  /// @brief const/volatile改造？ ポインタ、参照等は参照先をconst/volatile化する。
  /// @tparam T : const/volatile改造する型。
  /// @par Example
  /// AlterCV<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AlterCV
    : zzc_type_< typename AlterConst< typename AlterVolatile<T>::type >::type >{};

  // _____________________________________________________________________________
  /// @brief 非const/非volatile改造？ ポインタ、参照等は参照先を非const/非volatile化する。
  /// @tparam T : const/volatile改造する型。
  /// @par Example
  /// RefineCV<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct RefineCV
    : zzc_type_< typename RefineConst< typename RefineVolatile<T>::type >::type >{};

  // _____________________________________________________________________________
  /// @brief ポインタ修飾。
  /// @tparam T : ポインタ修飾する型。
  /// @par Example
  /// AddPointer<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AddPointer     : zzc_type_<T*>{};
  /// @cond
  template<class T> struct AddPointer<T&> : zzc_type_<T*>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief ポインタ型を取り除いた型を取得。
  ///
  /// ※ ポインタ型でない場合はそのまま。
  ///    const/volatile修飾は外される。
  /// @par Example
  /// RemovePointer<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct RemovePointer              : zzc_type_<T>{};
  /// @cond
  template<class T> struct RemovePointer<T*>          : zzc_type_<T>{};
  template<class T> struct RemovePointer<T* const>    : zzc_type_<T>{};
  template<class T> struct RemovePointer<T* volatile> : zzc_type_<T>{};
  template<class T> struct RemovePointer<T* cpl_cv>   : zzc_type_<T>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief ポインタ型変換。
  ///
  /// ※ const/volatile修飾は外さない。
  ///    ポインタ型はそのまま（ポインタのポインタを返すわけではない）
  /// @par Example
  /// AlterPointer<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AlterPointer     : zzc_type_<T*>{};
  /// @cond
  template<class T> struct AlterPointer<T*> : zzc_type_<T*>{};
  template<class T> struct AlterPointer<T&> : zzc_type_<T*>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief ポインタ型を取り除いた型を取得。
  ///
  /// ※ ポインタ型でない場合はそのまま。
  ///    const/volatile修飾は外される。
  /// @par Example
  /// UnPointer<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct ClearPointer              : zzc_type_<T>{};
  /// @cond
  template<class T> struct ClearPointer<T*>          : zzc_type_<typename ClearPointer<T>::type>{};
  template<class T> struct ClearPointer<T* const>    : zzc_type_<typename ClearPointer<T>::type>{};
  template<class T> struct ClearPointer<T* volatile> : zzc_type_<typename ClearPointer<T>::type>{};
  template<class T> struct ClearPointer<T* cpl_cv>   : zzc_type_<typename ClearPointer<T>::type>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 参照型修飾。
  /// @par Example
  /// AddReference<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AddReference     : zzc_type_<T&>{};
  /// @cond
  template<class T> struct AddReference<T&> : zzc_type_<T&>{};
  template<>        struct AddReference<void>          : zzc_type_<void>{};
  template<>        struct AddReference<void const>    : zzc_type_<void const>{};
  template<>        struct AddReference<void volatile> : zzc_type_<void volatile>{};
  template<>        struct AddReference<void cpl_cv>   : zzc_type_<void cpl_cv>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 参照型を取得。
  /// 
  /// ※ const/volatile修飾は外さない。\n
  /// 　 参照型はそのまま（参照型の参照を返すわけではない）\n
  /// 　 ポインタ型は参照型へ変換される。
  /// @par Example
  /// AlterReference<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct AlterReference     : AddReference<T>{};
  /// @cond
  template<class T> struct AlterReference<T*> : zzc_type_<T&>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 参照型を取り除いた型を取得。
  /// @par Example
  /// RemoveReference<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct RemoveReference     : zzc_type_<T>{};
  /// @cond
  template<class T> struct RemoveReference<T&> : zzc_type_<T>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 配列型を取り除いた型を取得。
  /// @par Example
  /// UnArray<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct RemoveArray       : zzc_type_<T>{};
  /// @cond
  template<class T>       struct RemoveArray<T[]>  : zzc_type_<T>{};
  template<class T,int N> struct RemoveArray<T[N]> : zzc_type_<T>{};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief const/volatile、ポインタ型・参照型・配列型を外した型を取得。
  /// @par Example
  /// Refine<T>::type
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct Refine
    : zzc_type_
      < typename RemoveArray
        < typename RemoveReference
          < typename RemovePointer
            < typename RemoveCV<T>::type
            >::type
          >::type
        >::type
      >{};

  // _____________________________________________________________________________
  /// @brief const修飾されていれば真に評価。
  /// @par Example
  /// IsConst<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct IsConst          : zzc_false_ {};
  /// @cond
  template<class T> struct IsConst<T const> : zzc_true_ {};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief volatile修飾されていれば真に評価。
  /// @par Example
  /// IsVolatile<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct IsVolatile             : zzc_false_ {};
  /// @cond
  template<class T> struct IsVolatile<T volatile> : zzc_true_ {};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief ポインタ型判定。
  ///
  /// ポインタならば真に評価。
  /// @par Example
  /// IsPointer<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct IsPointer            : zzc_false_ {};
  /// @cond
  template<class T> struct IsPointer<T*>        : zzc_true_ {};
  template<>        struct IsPointer<nullptr_t> : zzc_true_ {};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 参照型判定。参照型ならば真に評価。
  /// @par Example
  /// IsReference<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct IsReference     : zzc_false_ {};
  /// @cond
  template<class T> struct IsReference<T&> : zzc_true_ {};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 配列型判定。配列型ならば真に評価。
  ///
  /// IsArray<T>::value = 配列要素数となる。ただし、要素指定が無い場合-1となる。
  /// @par Example
  /// IsArray<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>       struct IsArray       : zzc_num_<0> {};
  /// @cond
  template<class T>       struct IsArray<T[]>  : zzc_num_<-1> {};
  template<class T,int N> struct IsArray<T[N]> : zzc_num_<N> {};
  /// @endcond

  // _____________________________________________________________________________
  /// @brief void型判定。void型ならば真に評価。
  /// @par Example
  /// IsVoid<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct IsVoid
    : zzc_bool_< IsSame< typename RemoveCV<T>::type, void >::value > {};

  // _____________________________________________________________________________
  /// @brief 識別子。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  struct ID
  {
  private:
  public:
    // cv types
    template<class T>
    using CVTypes = TupleType<T, T const, T volatile, T const volatile>;

    using Char       = CVTypes<char>;
    using UChar      = CVTypes<unsigned char>;
    using Short      = CVTypes<short>;
    using UShort     = CVTypes<unsigned short>;
    using Int        = CVTypes<int>;
    using UInt       = CVTypes<unsigned int>;
    using Long       = CVTypes<long>;
    using ULong      = CVTypes<unsigned long>;
    using LongLong   = CVTypes<long long>;
    using ULongLong  = CVTypes<unsigned long long>;
    using Int64      = CVTypes<S64>;
    using UInt64     = CVTypes<U64>;
    using Float      = CVTypes<float>;
    using Double     = CVTypes<double>;
    using LongDouble = CVTypes<long double>;

    /// @brief 整数型識別子。
    using Integral =
      TupleType
        <Char, UChar, Short, UShort, Int, UInt
        ,Long, ULong, LongLong, ULongLong, Int64, UInt64
        >;

    /// @brief 不動小数点型識別子。
    using FloatingPoint = TupleType< Float, Double, LongDouble >;

    /// @brief 算術型識別子。
    using Arithmetic = TupleType< Integral, FloatingPoint >;

    /// @brief 単純型識別子。
    using Fundamental = TupleType< Arithmetic, void, nullptr_t >;
  };

  // _____________________________________________________________________________
  /// @brief 整数型判定。整数型ならば真に評価。
  /// @par Example
  /// IsInteger<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>
  struct IsInteger
    : zzc_bool_< IsCompare< T, ID::Integral >::value >
  {};

  // _____________________________________________________________________________
  /// @brief 実数型判定。実数型ならば真に評価。
  /// @par Example
  /// IsFloat<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>
  struct IsFloat
    : zzc_bool_< IsCompare< T, ID::FloatingPoint >::value >
  {};

  // _____________________________________________________________________________
  /// @brief 算術型判定。算術型なら真に評価。
  /// @par Example
  /// IsArithmetic<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>
  struct IsArithmetic
    : zzc_bool_< IsCompare< T, ID::Arithmetic >::value >
  {};

  // _____________________________________________________________________________
  /// @brief 基本データ型判定。基本データ型なら真に評価。
  /// @par Example
  /// IsFundamental<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T>
  struct IsFundamental
    : zzc_bool_< IsCompare< T, ID::Fundamental >::value >
  {};

  // _____________________________________________________________________________
  /// @brief 仮想化判定。仮想化されている場合、真に評価。
  /// @par Example
  /// IsPolymorphic<T>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T> struct IsPolymorphic
  {
  private:
    typedef typename RemovePointer< typename RemoveReference<T>::type >::type T_Type;
    struct zzc_dummy{};
    struct zzca : IfType<IsFundamental<T_Type>::value, zzc_dummy, T_Type>::type {};
    struct zzcb : IfType<IsFundamental<T_Type>::value, zzc_dummy, T_Type>::type { virtual ~zzcb() throw() {} };
  public:
    static const int value = zzc_bool_<sizeof(zzca)==sizeof(zzcb)>::value;
  };

  //// _____________________________________________________________________________
  ///// @brief
  ///// 指定された型がポインタサイズ以下ならそのままの型を、それ以外なら参照型を表す。
  ///// @par Example
  ///// BetterReference<T>::type
  //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //template<class T>
  //struct BetterReference
  //  : IfType< (sizeof(T)<=sizeof(void*)), T, T& >
  //{};


  // _____________________________________________________________________________
  /// @brief 静的キャスト用。
  /// @par Example
  /// StaticCast<T>( x )
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T, class U>
  struct StaticCast { static T Cast( U in_type ){ return static_cast<T>(in_type); } };
  /// @cond
  template<class T>
  struct StaticCast<T,T> { static T Cast( T in_type ){ return in_type; } };
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 動的キャスト用。
  /// @par Example
  /// DynamicCast<T>( x )
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T, class U>
  struct DynamicCast { static T Cast( U in_type ){ return dynamic_cast<T>(in_type); } };
  /// @cond
  template<class T>
  struct DynamicCast<T,T> { static T Cast( T in_type ){ return in_type; } };
  /// @endcond

  // _____________________________________________________________________________
  /// @brief 複数キャストチェック。
  ///
  /// キャスト可能な個数がvalueに設定される。
  /// @tparam T_From   : 変換元の型。
  /// @tparam T_To0    : 変換チェックする最初の型。
  /// @tparam T_Params : ２つ以上チェックする場合は指定する。
  /// @par Example
  /// IsCasts<A, B,C>::value
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_From, class T_To0, class... T_Params>
  struct IsCasts
  {
  private:
    template<int N, class F, class T, class... Ts>
    struct Count_
      : Count_< N + std::is_convertible<F, T>::value, F, Ts... >
    {};
    template< int N, class F, class T>
    struct Count_<N, F, T>
      : zzc_num_< N + std::is_convertible<F, T>::value >
    {};
  public:
    static const int value = Count_<0, T_From, T_To0, T_Params...>::value;
  };

  // _____________________________________________________________________________
  /// @brief 優先順位付きキャスト。
  /// 
  /// 指定された型の中で、キャスト可能な最も優先順位の高い型をtypeに設定。
  /// @tparam T_From   : 変換元の型。
  /// @tparam T_To0    : 最も優先する型。
  /// @tparam T_Params : T_To0に続く優先度の型の列挙。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_From, class T_To0, class... T_Params>
  struct PriorityCast
  {
  private:
    /// @cond
    template<int B, class F, class T, class... Ts>
    struct Cast_{};

    template<class F, class T, class... Ts>
    struct Cast_<false, F, T, Ts...>
      : Cast_<std::is_convertible<F, T>::value, F, Ts...>
    {};

    template<class F, class T, class... Ts>
    struct Cast_<true, F, T, Ts...> : zzc_type_<T> {};

    template<class F, class T>
    struct Cast_<true, F, T> : zzc_type_<T> {};
    /// @endcond
  public:
    typedef typename Cast_<false, T_From, T_To0, T_Params...>::type type;
  };


  // _____________________________________________________________________________
  /// @brief TとUを比較し、より精度の高い基本型をtypeに設定する。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T, class U>
  struct Accurate
    : IfType
      < IsCompare<long double,T,U>::value
      , long double
      , typename IfType< IsCompare<double,T,U>::value, double
      , typename IfType< IsCompare<float, T,U>::value, float
      , typename IfType< IsCompare<U64,   T,U>::value, U64
      , typename IfType< IsCompare<S64,   T,U>::value, S64
      , typename IfType< IsCompare<unsigned long, T,U>::value, unsigned long
      , typename IfType< IsCompare<long,          T,U>::value, long
      , typename IfType< IsCompare<unsigned int,  T,U>::value, unsigned int
      , typename IfType< IsCompare<int,           T,U>::value, int
      , typename IfType< IsCompare<U16,   T,U>::value, U16
      , typename IfType< IsCompare<S16,   T,U>::value, S16
      , typename IfType< IsCompare<U8,    T,U>::value, U8
      , typename IfType< IsCompare<S8,    T,U>::value, S8
      , void // other
      >::type // S8 or void
      >::type // U8
      >::type // S16
      >::type // U16
      >::type // int
      >::type // unsigned int
      >::type // long
      >::type // unsigned long
      >::type // S64
      >::type // U64
      >::type // float
      >::type // double
      > // long double
  {};

  // _____________________________________________________________________________
  /// @brief CV修飾のコピー。
  /// 
  /// TのCV修飾をUに適応する。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T, class U> struct CopyType : zzc_type_<U> {};
  /// @cond
  template<class T, class U> struct CopyType<T*,U> : AlterPointer<U> {};
  template<class T, class U> struct CopyType<T const*,U> : AlterPointer<U const> {};
  template<class T, class U> struct CopyType<T&,U> : AlterReference<U> {};
  template<class T, class U> struct CopyType<T const&,U> : AlterReference<U const> {};
  /// @endcond
//private:
  // 数値の比較
  template<int a, int b, bool f> struct min_{};
  template<int a, int b>
  struct min_<a,b,false>
  {
    static const int min = b;
    static const int max = a;
  };
  template<int a, int b>
  struct min_<a,b,true>
  {
    static const int min = a;
    static const int max = b;
  };
//public:
  template<int a, int b> struct NumComp : min_<a,b,(a<b)> {};
};


///// @cond
//template<> struct Traits::zzc_bool_<false> : zzc_false_ {};
//
//template<class T>
//  struct Traits::IsSame<T, T> : zzc_true_{};
//template<class T, class... T_Params>
//  struct Traits::IsSame<T, T, T_Params...> : IsSame<T, T_Params...>{};
//
//template<template<class... U> class T>
//  struct Traits::IsSameT<T<>, T<>> : zzc_true_{};
//template<template<class... U>class T, class... T_Params>
//  struct Traits::IsSameT<T<>, T<>, T_Params...> : IsSame<T<>, T_Params...>{};
//
//template<class T> struct Traits::AddReference<T&> : zzc_type_<T&>{};
//template<>        struct Traits::AddReference<void>          : zzc_type_<void>{};
//template<>        struct Traits::AddReference<void const>    : zzc_type_<void const>{};
//template<>        struct Traits::AddReference<void volatile> : zzc_type_<void volatile>{};
//template<>        struct Traits::AddReference<void cpl_cv>   : zzc_type_<void cpl_cv>{};
///// @endcond

template<class T, class U> using tt_CopyType = typename Traits::CopyType<T,U>::type;


//} // namespace Core
} // namespace CPL
