I'm trying to wrap my head around how template templates work to implement a similar functionality as shown below.
Consider two classes (in Java). The first class is limiting the collection returned by pack
method by specifying that only an object of the second template argument can be stored in it:
abstract class ContainerPacker<T, Container extends Collection<T>> {
abstract Container pack(T t);
}
And implementation of this class for, let's say, Integer
type could then look like this:
class IntegerContainerPacker extends ContainerPacker<Integer, List<Integer>> {
@Override
List<Integer> pack(Integer t) {
List<Integer> list = new ArrayList<>(t);
list.add(t);
return list;
}
}
Now I'd like to do something similar in C++ using template templates. Notice how the Container
is a template itself:
template <typename T, template <typename U> class Container>
class ContainerPacker {
public:
virtual Container<T> pack(T) = 0;
};
I'm having trouble implementing it though. The code below does not compile:
class IntegerVectorPacker : public ContainerPacker<int, std::vector> {
public:
std::vector<int> pack(int t) {
std::vector<int> v = std::vector<int>();
v.push_back(t);
return v;
}
};
The errors are:
error: type/value mismatch at argument 2 in template parameter list for ‘template class Container> class ContainerPacker’ class IntegerVectorPacker : public ContainerPacker {
and
note: expected a template of type ‘template class Container’, got ‘template class std::vector’
I've been looking for an answer but it's even difficult to figure out what question to ask. Template templates are hard.
Try with
template <typename T, template <typename...> class Container>
The problem (a problem?) in your code is that std::vector
is a template class that receive more than one templates argument (two: the second one has a default type); so doesn't match Container
.
Defining Container
as receiving zero or more templates should permit the match with std::vector<int>
(that really is std::vector<int, std::allocator<int>>
) and other containers.
-- EDIT --
I see now that you have tagger this question C++ and not C++11 (or newer).
The typename...
suggestion is valid only starting from C++11 because variadic templates aren't available before.
For C++98 you can write
template <typename T, template <typename, typename> class Container>
but this works only with two parameters containers.
-- EDIT 2 --
Off Topic suggestion.
If you can use C++11 or newer (so variadic templates) switch the order of Container
and T
for ContainerPacker
and transform T
is a variadic pack; something like
template <template <typename...> class Container, typename ... Ts>
class ContainerPacker {
public:
virtual Container<Ts...> pack(Ts...) = 0;
};
It's much more flexible.