Syntax for define a template that takes a template

243 views Asked by At

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?

Live example.

1

There are 1 answers

10
Enlico On BEST ANSWER

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.