#include <type_traits>

namespace tmpalg {
  template <typename... T> struct type_list;
  template <typename T> using identity = T;

  template <typename TL>
  using size = std::integral_constant<int, -1>; // size::value contains the number
                                                // of types in type_list<T...>

  template <typename TL, int N>
  using at = void; // Nth type in TL=type_list<T...>  (zero based)

  template <typename TL, template <typename> class F>
  using transform = void; // type_list<T...> becomes type_list<F<T>...>

  template <typename TL, template <typename> class Pred=identity>
  using filter = void; // returns a type_list where for every element T
                       // Pred<T>::value == true holds 

  template <typename TL, template <typename> class Pred=identity>
  using all_of = std::false_type; // all_of<...>::value == true if
                                  // Pred<T>::value == true for all T in TL

  template <typename TL, template <typename> class Pred=identity>
  using any_of = std::false_type; // all_of<...>::value == true if
                                  // Pred<T>::value == true for at least one T in TL

  template <typename TL, template <typename> class Pred=identity>
  using none_of = std::false_type; // all_of<...>::value == true if
                                   // Pred<T>::value == true for no T in TL
}

template <typename T> struct test;

int main()
{
  using namespace tmpalg;

  using list = type_list<int /*0*/, char /*1*/, long /*2*/,
                         float /*3*/, short /*4*/, void /*5*/,
                         double /*6*/, int /*7*/>;
  static_assert(size<list>::value == 8, "size fails");
  static_assert(size<type_list<> >::value == 0, "size fails");
  static_assert(std::is_same<at<list, 3>, float>::value, "at fails");
  static_assert(std::is_same<transform<list, identity>, list>::value, "transform fails");  
  static_assert(std::is_same<at<transform<list, test>, 1>, test<char> >::value, "transform fails");
  static_assert(size<transform<list, test> >::value == size<list>::value, "transform fails");
  static_assert(size<filter<list, std::is_integral> >::value == size<list>::value - 3, "filter fails");
  static_assert(all_of<filter<list, std::is_integral>, std::is_integral>::value, "all_of fails");
  static_assert(!all_of<list, std::is_integral>::value, "all_of fails");
  static_assert(any_of<list, std::is_integral>::value, "any_of fails");
  static_assert(!any_of<list, std::is_pointer>::value, "any_of fails");
  static_assert(none_of<list, std::is_pointer>::value, "none_of fails");
  static_assert(!none_of<list, std::is_fundamental>::value, "none_of fails");

  /* these lines should not compile (if you remove the comments) */
  //using X = at<999, list>;
  //using Y = at<0, void>;
  //auto Z = size<void>::value;
}
