Reputation: 280
I'm trying to understand C++ template templates by implementing a generic container class. Here is the code:
using namespace std;
template <typename T, template <typename STORETYPE> class Container>
class Store {
public:
~Store() {};
Store() {};
void someFunc( const T & ) {};
//...
private:
Container<T> storage;
};
int main(int argc, char *argv[])
{
Store<int,deque> myStore; // error here, won't compile!
}
The code above generates a compiler error message. The error message is:
"template template argument has different template parameters than its corresponding template template parameter Store aStack1;
I don't know why. What's wrong?
Upvotes: 4
Views: 295
Reputation: 15528
As an alternative to the answer by @TartanLlama, you can also use an alias for deque
.
template<typename T>
using deque_alias = deque<T>;
int main(int argc, char *argv[])
{
Store<int,deque_alias> myStore; // now it will compile!
}
Then also the default template parameters (here std::allocator<T>
) are used correctly. (Some compilers like MSVC have problems with that and will fail otherwise, as they expect two template parameters, see here for example).
Upvotes: 1
Reputation: 65770
Your issue is that std::deque
(and other standard containers) doesn't just take a single template argument. As well as the stored type, you can specify an allocator functor type to use.
If you don't care about these additional arguments, you can just take a variadic template template and be on your way:
template <typename T, template <typename...> class Container>
// variadic ^^^
class Store {
If you also want to support passing of optional arguments to your container type, you can forward them on like this:
template <template <typename ...> class Container, typename T, typename... ContainerArgs>
class Store {
//...
Container<T,ContainerArgs...> storage;
};
Then instantiate like so:
Store<deque,int> myStore;
Store<deque,int,MyIntAllocator> mySpecialStore;
However, you might just want to extract the template arguments using specialization:
template <typename Container>
class Store;
template <template <typename...> class ContainerType, typename T, typename... OtherArgs>
class Store<ContainerType<T,OtherArgs...>>
{
//...
};
This will let client code instantiate like this:
Store<deque<int>> myStore;
Store<deque<int,MyIntAllocator>> mySpecialStore;
Store<T> myOtherStore; //where T is some specialized container type
Upvotes: 6
Reputation: 41341
std::deque
is defined as
template <class T, class Allocator = allocator<T> > class deque;
So you should change the definition of Store
to match:
template <typename T, template <typename...> class Container>
class Store {
But actually you don't even need template template parameters for this. You can achieve even more generality just passing a container type as parameter, so for example Storage
would support even std::map
:
template <typename Container>
class Store {
public:
using value_type = typename Container::value_type;
~Store() {};
Store() {};
void someFunc( const value_type& ) {};
//...
private:
Container storage;
};
Store<std::map<int, float>> myStore;
Upvotes: 1