Gabor Marton
Gabor Marton

Reputation: 2099

How to specialize a class template with a template template parameter?

I'd like to specialize a class template on the type template parameter of the template template parameter. Is it possible? If yes, what is the syntax?

#include <type_traits>

template <typename T>
struct X {};

// primary template
template<template<class> class C>
struct Z : std::false_type {};

// specialization on the template template parameter
template<>
struct Z<X> : std::true_type {}; // OK

// specialization on the type template parameter of the
// template template parameter
template <template<class> class C>
struct Z<C<int>> {}; // ERROR

Motivation: Let's assume that the template template parameter denotes Collections (e.g. std::vector, std::deque). And I want to specialize Z on std::vector but I am not interested about the type template parameter of std::vector, that's OK. Also I want to specialize on all Collection types, which holds an int.

This question is similar to the following questions, but they are either trying to specialize a function template

or they are trying to specialize not on the template template parameter

or there's no template template parameter in the primary template

Upvotes: 2

Views: 2580

Answers (2)

Ralph Tandetzky
Ralph Tandetzky

Reputation: 23590

The following code compiles fine:

#include <type_traits>

template <typename T>
struct X {};

// primary template, no template template parameter
template<typename T>
struct Z : std::false_type {};

// specialization on the template template parameter with arbitrary T
template<typename T>
struct Z<X<T>> : std::true_type {};

// here's where you need the template template parameter
template <template<class> class C>
struct Z<C<int>> : std::true_type {};

int main()
{
    static_assert(!Z<Z<double>>::value, "" );
    static_assert( Z<Z<int   >>::value, "" );
    static_assert( Z<X<double>>::value, "" );
//  static_assert( Z<X<int   >>::value, "" ); // error: ambiguous 
                                              // partial specialization
}

In your code you give Z a template template parameter, even though that should be done for the specialization only. That's why your code does not compile.

Upvotes: 2

Abstraction
Abstraction

Reputation: 511

This cannot work because in your code:

template<template<class> class C>
struct Z : std::false_type {};
template<>
struct Z<X> : std::true_type {};

Z expects class template as a parameter.

template <template<class> class C>
struct Z<C<int>> {};

Here you are are not specializing any of it's template arguments and trying to pass C<int> which is not a class template (C is a class template and is different than C<int> which is concrete type).

If your class has template parameter which is a class template and you want your class to behave differently for different types passed for the container you probably should do something like:

template<template <typename> class Container,typename Element>
struct MyStruct
{
    Container<Element> generic_elements;
    // ...
};

template<template <typename> class Container>
struct MyStruct<Container,int>
{
    Container<int> special_int_container;
    void special_int_things();
    //...
};

Upvotes: 1

Related Questions