Template Template Argument

Viewed 62

I want to implement a function that shows different template classes that share the same characteristics (but are not necessarily in an inheritance relationship). I've written the following code below, but the compiler doesn't seem to be able to match the calling of show() to it's template. It says:

  1. string_int - "invalid explicit-specified argument for template MAP"
  2. string_string - "template template argument has different template parameters than its corresponding template template parameter" (it does match KEY and VALUE properly, though)

Can you help?

#include <iostream>
#include <string>

#include <map>

using namespace std;

template <class KEY, class VALUE, template<class, class> class MAP>
void show(string title, MAP<KEY, VALUE> &map)
{
    cout << title << ":\n";
    for (auto &i: map) cout << i.first << " - " << i.second << endl;
    cout << endl;
}

int main(int, const char *[])
{
    map<string, int> string_int;
    multimap<string, string> string_string;
    
    string_int["Mike"] = 50;
    string_int["Ann"] = 58;
    string_int["John"] = 39;
    string_int["Louise"] = 37;
    show<string, int, map<string, int>>("string_int", string_int);

    string_string.insert({ "Mike", "Self" });
    string_string.insert({ "Ann", "Spouse" });
    string_string.insert({ "John", "Friend" });
    string_string.insert({ "John", "Co-worker" });
    string_string.insert({ "Louise", "Friend" });
    string_string.insert({ "Louise", "Bridge partner" });
    show("string_string", string_string);

    return 0;
}
1 Answers

Your template template parameter in show is restricted to accept class templates that have exactly two template parameters. However, std::map has more than two template parameters, and hence the deduction fails.

You can fix this by making the template parameters of the template template parameter variadic:

template <class KEY, class VALUE, template<class ...> class MAP>
                                              // ^^^ 
void show(string title, MAP<KEY, VALUE> &map);

Now argument deduction will work in this case:

show("string_string", string_string);  // ok

However, when you specify the template parameters explicitly:

show<string, int, map<string, int>>("string_int", string_int);  // error

that doesn't work, because map<string, int> is a concrete type, not a template type.

Instead, you need to specify just map, since that is the template type you want for the template template parameter:

show<string, int, map>("string_int", string_int);   // ok

Here's a demo.

Related