Search code examples
c++c++11templatescontainersmultimap

More templates in C++?


My assignment is to make a multimap_util template class that helps the using of multimap. My main problem is that the multimap_util class should also work with custom sorted multimaps.

I don't know how to make it work with two different templates.

So with 2 template args like this:

std::multimap<int, int> m;
multimap_util<int, int> mu( m );

and with 3 template args like this:

std::multimap<std::string, std::string, string_size_more> lmm;
multimap_util<std::string, std::string, string_size_more> lmmu( lmm );

Here is my code:

template <typename T1, typename T2, typename C>
class multimap_util
{
        std::multimap<T1, T2, C>* map;
        
    public:
        multimap_util(std::multimap<T1,T2>& map) : map(&map)
        {};
        
        multimap_util(std::multimap<T1,T2,C>& map) : map(&map)
        {};
.
.
.
}

I always get errors like this:

error: wrong number of template arguments (2, should be 3)
   66 |   multimap_util<std::string, std::string> langsu( langs );

It has to be done without variadic template.

I red about template partial specialization but I don't know how it works. I also thought about making a child class with a different template that derives from the util class?


Solution

  • Take in count that std::multimap has ever 4 template parameter. But with a default for the third and the fourth template parameter.

    It seems to me that the best you can do is emulate the std::multimap signature that is

    template<
    
        class Key,
        class T,
        class Compare = std::less<Key>,
        class Allocator = std::allocator<std::pair<const Key, T> >
    > class multimap;
    

    you could write your class as follows

    template <typename K, typename V,
              typename C = std::less<K>,
              typename A = std::allocator<std::pair<K const, V>>>
    class multimap_util
     {
       private: 
          std::multimap<K, V, C, A>* map;
            
       public:
          multimap_util (std::multimap<K, V, C, A> & m) : map{&m}
           {};
     };
    

    This works with

    std::multimap<int, int> m;
    multimap_util<int, int> mu( m );
    

    because it's equivalent to

    std::multimap<int, int, std::less<int>, std::allocator<std::pair<int const, int>> m;
    multimap_util<int, int, std::less<int>, std::allocator<std::pair<int const, int>> mu( m );
    

    and works also when you declare a multimap_util with 3 or 4 template parameter: are ever 4 but some of them can be defaulted.

    Unfortunately you can't use C++17 or C++20 because starting from C++17 is available CTAD (Class Template Argument Deduction) so you can also write

    std::multimap<int, int> m;
    multimap_util           mu( m ); // <-- CTAD at works
    

    and all template parameters, for multimap_utils, are deduced from the m argument.

    To simplify your life, also in C++11 you can write a make_multimap_util() function as follows

    template <typename K, typename V, typename C, typename A>
    multimap_util<K, V, C, A> make_multimap_util (std::multimap<K, V, C, A> & m)
     { return {m}; }
    

    so, using the power of the auto placeholder, you can simply write

    std::multimap<int, int> m;
    
    auto mu = make_multimap_util(m);
    

    and mu become a multimap_util<int, int> or, its the same thing, multimap_util<int, int, std::less<int>, std::allocator<std::pair<int const, int>>.