#include <iostream>
#include <typeinfo>

template
	<
		template <typename...> class BeCurry,
		typename... Params
	>
struct Curry
{
	using type = BeCurry<Params...>;
};

template
	<
		template <typename...> class BeCurry
	>
struct Curry<BeCurry>
{
	using type = BeCurry<>;
};

template
	<
		template <typename...> class BeCurry,
		typename... Params
	>
struct Currying
{
	template <typename... OtherParams>
	using curried = typename Curry<BeCurry, Params..., OtherParams...>::type;

	template <typename... OtherParams>
	using type = typename curried<OtherParams...>::type;
	
	template <typename... NewParams>
	using apply = Currying<curried, NewParams...>;
};

template<typename T>
struct Test1
{
	using type = int;
};

template<typename T, typename T1>
struct Test2
{
	using type = char*;
};

template <typename T>
void print_type(T t)
{
	std::cout << typeid(t).name() << std::endl;
}

int main()
{
	print_type(Currying<Test1>::type<int>{});
	print_type(Currying<Test1>::apply<int>::type<>{});
	print_type(Currying<Test2>::type<int, char>{});
	print_type(Currying<Test2>::apply<int>::type<char>{});
	print_type(Currying<Test2>::apply<int>::apply<char>::type<>{});
	print_type(Currying<Test2>::apply<int, char>::type<>{});
	return 0;
}