2

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

Community
  • 1
  • 1
Gabor Marton
  • 2,039
  • 2
  • 22
  • 33
  • I do not understand what you are trying to do. If the type of "specialization" you are trying to do were allowed, under what circumstances would that specialization be instantiated? The argument to `Z` is a template, not a type. – Brian Bi Dec 22 '15 at 23:47

2 Answers2

2

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.

Ralph Tandetzky
  • 22,780
  • 11
  • 73
  • 120
1

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();
    //...
};
Abstraction
  • 511
  • 2
  • 9