I have a class that needs to use some sort of map. By default, I want to use std::map
, but I also want to give the user the ability to use something different if they want (e.g. std::unordered_map
or maybe even a user created one).
So I have code that looks like
#include <map>
template<class Key, template<class, class> class Map = std::map>
class MyClass {
};
int main() {
MyClass<int> mc;
}
But then, g++ complains
test.cpp:3:61: error: template template argument has different template parameters than its corresponding template template parameter
template<class Key, template<class, class> class Map = std::map>
^
test.cpp:8:14: note: while checking a default template argument used here
MyClass<int> mc;
~~~~~~~~~~~^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/map:781:1: note: too many template parameters in template template argument
template <class _Key, class _Tp, class _Compare = less<_Key>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:3:21: note: previous template template parameter is here
template<class Key, template<class, class> class Map = std::map>
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
So it looks like g++
is unhappy that std::map
has default arguments.
Is there a way I can allow Map
to be any sort of template that can accept at least two template arguments?
I would prefer to stick with C++98 if I can, but I'm open to C++11.
The problem is that your template template parameter has only two template parameters, as opposed to map
, which has four.
template<class Key, template<class, class, class, class> class Map = std::map>
class MyClass {
};
Or
template<class Key, template<class...> class Map = std::map>
class MyClass {
};
Should compile.
However, to avoid such problems, try to take the map type instead, and extract the key type via the corresponding member typedef. E.g.
template <class Map>
class MyClass {
using key_type = typename Map::key_type;
};
Your code will compile in C++17. A long-standing defect report of the C++ Core Working Group (CWG 150) was resolved (by P0522R0) in time for C++17.
cppreference.com also discuss this here, and include a helpful example:
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };
template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
// Error earlier: not an exact match
X<C> xc; // OK in C++17 after CWG 150
// Error earlier: not an exact match
Testing with my version of GCC (8.3.0), I find that using the -std=c++17
flag will successfully compile your program; while using earlier versions of C++ (e.g. -std=c++14
or -std=c++11
) will fail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With