Yes, with template template template arguments:
template <template <typename, typename> class M, typename K, typename V>
void Foo(M<K, V> & container)
{
// ...
};
Note that this will never match any real-word container, though, because those have many more template arguments. Better with variadics:
template <template <typename, typename, typename...> class M, typename K, typename V, typename ...Args>
void Foo(M<K, V, Args...> & container)
{
// ...
};
If variadics aren't an option, you could leverage a bit of wrapping yourself:
template <typename Container> void FooImpl(Container &);
template <template <typename, typename> class M,
typename K, typename V>
void Foo(M<K,V> & c) { FooImpl(c); }
template <template <typename, typename, typename> class M,
typename K, typename V, typename A1>
void Foo(M<K,V,A1> & c) { FooImpl(c); }
template <template <typename, typename, typename, typename> class M,
typename K, typename V, typename A1, typename A2>
void Foo(M<K,V,A1,A2> & c) { FooImpl(c); }
// etc.
For reference, std::unordered_map
takes five template parameters (key, value, hash functor, equality predicate, allocator). Boost's bimap
might take even more.
Abuse of this last construction could be prevented by making the functions static members of a wrapper class and making the implementation private, and by providing a single free accessor helper function.