Today I learned that this is completely valid, and in fact useful:
template<template <typename, typename, typename...> class Map, typename Key, typename Value>
This is a template template parameter (yes, two templates). This is a type of template specialization, which allows the caller to pass any type which contains two template parameters. Issue is, that since the example shows a map/key/value (which would be useful for a common implementation between map or unordered_map), it doesn't actual prevent the caller from abusing it and passing in any type. For example:
template<typename T1, typename T2>
struct SomeType {};
SomeType<int, float> instance;
function(instance, ...);
Is completely valid (if a type looks like a duck and quacks like a duck then it can be used as a duck in the template). You can restrict this by using SFINAE:
template <typename T, typename = void>
struct is_map_like : std::false_type {};
template <typename T>
struct is_map_like<T, typename std::enable_if<
std::is_same<typename T::key_type, typename T::key_type>::value &&
std::is_same<typename T::mapped_type, typename T::mapped_type>::value
>::type> : std::true_type {};
The std::enable_if (relies-upon SFINAE) will disable the template if the passed type does not satisfy the type constraints. In some cases this is useful since you could have tons of similar classes and don't want to specify a specific function overload for each type. You can take this even further and define more specific template template parameter template functions to specify your generic templates (a mouthful I know...):
template<template <typename, typename, typename...> class Map, typename Key, typename Value>
void function(const Map<Key, Value>& m, std::function<void(Key, Value)> func, typename std::enable_if<is_map_like<Map<Key, Value>>::value>::type* = 0) { }
template<template <typename, typename, typename...> class OtherType, typename T1, typename T2>
void function(const OtherType<T1, T2>& ot, std::function<void(T1, T2)> func, typename std::enable_if<!is_map_like<OtherType<T1, T2>>::value>::type* = 0) { }
This still uses SFINAE with the familiar type traits, but enables calling the same function with the same number of template template parameters, while getting different behavior based on the type that was passed in. Useful, but in very specific scenarios.
C++ 20 allows use of these concepts, but much simpler.