I wanted to create a type that holds a generic type type, that, itself, is a template with one argument. So, if my type is called C
, it could be summarized like C<T<U>>
.
So, I went for it:
#include <vector>
template <template<typename> class T>
class C
{
// implementation here
};
int main() {
C<std::vector<int>> myType;
}
And I am facing this error:
<source>:10:7: error: template argument for template template parameter must be a class template or type alias template
C<std::vector<int>> myType;
^
1 error generated.
ASM generation compiler returned: 1
What is the correct way of force a template to take a type that itself, is a template that expects other template argument?
You can specialize the class for the case you need and let it undefined otherwise
#include <vector>
template <typename T>
class C;
template <template<typename> typename TT, typename U>
class C<TT<U>>
{
// implementation here
};
int main() {
C<std::vector<int>> myType;
// C<int> myTypeWrong; // compile error
}
The above does not work before C++17 because std::vector
has a default for its second template type parameter,
template<
class T,
class Allocator = std::allocator<T>
> class vector;
and before C++17 the part = std::allocator<T>
is ignored, as far as matching the std::vector
template template argument with the TT
template template parameter above, so std::vector<T, std::allocator<T>>
never successfully match C<TT<U>>
. (Same thing holds for template<typename, typename = void> struct V {};
as it holds for std::vector
, clearly.)
This, together with the workaround mentioned in a comment and based on the usage of a variadic template parameter for the template template parameter, is explained in C++ Templates - The Complete Guide 2nd edition, §12.3.4, page 197-198.
As pointed out in another comment, Clang hasn't adopted the C++17 change to the mentioned part of the standard.