Currying is the technique of transforming a function that takes multiple arguments in such a way that it can be called as a chain of functions, each with a single argument. I've discussed Currying on this blog previously in Fun With Lambdas C++14 Style and Dependently-Typed Curried printf. Both blogposts discuss currying of functions proper. I.e., they discuss how C++ can treat functions as values at runtime.

However, currying is not limited to just functions. Types can also be curried---if they take type arguments. In C++, we call them templates. Templates are "functions" at type level. For example, passing two type arguments

So, the question today is: Can C++ templates be curried? As it turns out, they can be. Rather easily. So, here we go...

The technique is very simple. There's a function called

Note that C++ allows templates to have default type arguments. Therefore, a template could be instantiated by providing "minimum" number of arguments. For example,

When

However, currying is not limited to just functions. Types can also be curried---if they take type arguments. In C++, we call them templates. Templates are "functions" at type level. For example, passing two type arguments

`std::string`

and `int`

to `std::map`

gives `std::map<std::string, int>`

. So `std::map`

is a type-level function that takes two (type) arguments and gives another type as a result. They are also known as type constructors.
So, the question today is: Can C++ templates be curried? As it turns out, they can be. Rather easily. So, here we go...

#include <type_traits> #include <functional> #include <map> #include <iostream> template <template <class...> class C, class... T, class D = C<T...>> constexpr std::true_type valid(std::nullptr_t); template <template <class...> class C, class... T> constexpr std::false_type valid(...); template <class TrueFalse, template <class...> class C, class... ArgsSoFar> struct curry_impl; template <template <class...> class C, class... ArgsSoFar> struct curry_impl<std::true_type, C, ArgsSoFar...> { using type = C<ArgsSoFar...>; }; template <template <class...> class C, class... ArgsSoFar> struct curry_impl<std::false_type, C, ArgsSoFar...> { template <class... MoreArgs> using apply = curry_impl<decltype(valid<C, ArgsSoFar..., MoreArgs...>(nullptr)), C, ArgsSoFar..., MoreArgs...>; }; template <template <class...> class C> struct curry { template <class... U> using apply = curry_impl<decltype(valid<C, U...>(nullptr)), C, U...>; }; int main(void) { using CurriedIsSame = curry<std::is_same>; static_assert(curry<std::is_same>::apply<int>::apply<int>::type::value); curry<std::less>::apply<int>::type less; std::cout << std::boolalpha << less(5, 4); // prints false using CurriedMap = curry<std::map>; using MapType = CurriedMap::apply<int>::apply<long, std::less<int>, std::allocator<std::pair<const int, long>>>::type; static_assert(std::is_same<MapType, std::map<int, long>>::value); }Wandbox

The technique is very simple. There's a function called

`valid`

that has two overloads. The first one returns `std::true_type`

only if `C<T..>`

is a valid instantiation of template `C`

with argument list `T...`

. Otherwise, it returns `std::false_type`

. `C`

is type constructor that we would like to curry. This function uses the SFINAE idiom.
`curry_impl`

is the core implementation of template currying. It has two specializations. The `std::true_type`

specialization is selected when `valid`

returns `std::true_type`

. I.e., curried version of the type constructor has received the minimum number of type arguments to form a complete type. In other words, `ArgsSoFar`

are enough. `curry_impl<C, ArgsSoFar...>::type`

is same as instantiation of the type constructor with the valid type arguments (`C<ArgsSoFar...>`

).
Note that C++ allows templates to have default type arguments. Therefore, a template could be instantiated by providing "minimum" number of arguments. For example,

`std::map`

could be instantiated in three ways giving the same type:
`std::map<int, long>`

`std::map<int, long, std::less<int>>`

`std::map<int, long, std::less<int>, std::pair<const int, long>>`

When

`ArgsSoFar`

are not enough, `curry_impl<std::false_type>`

carries the partial list of type arguments (`ArgsSoFar`

) at class template level. It allows passing one or more type arguments (`MoreArgs`

) to the type constructor through the `apply`

typedef. When `ArgsSoFar`

and `MoreArgs`

are enough to form a valid instantiation, `curry_impl<std::true_type>`

is chosen which yields the fully instantiated type.
## Comments