How to specialize a class template with a template template parameter? - c++

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
How to specialize a template with template-tempate parameters
Specialize a template with a template
or they are trying to specialize not on the template template parameter
Specialization and template template parameters
or there's no template template parameter in the primary template
Templated class specialization where template argument is a template

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.

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();
//...
};

Related

Template template partial specialization failure: "expected a class template"

This example code generates expected a class template, got std::pair <_T1, _T2>. I tried using struct Struct <std::pair> {};, but then parameters T and M become undeducible. How to avoid this?
template <template <class...> class>
struct Struct {};
template <class T, class M>
struct Struct <std::pair <T, M>> {};
Depending of what you want
template <template <class...> class>
struct Struct {};
template <>
struct Struct <std::pair>
{
// Specialization
};
or
template <typename> struct Struct {};
template <typename First, typename Second>
struct Struct <std::pair<First, Second>>
{
// Specialization
};
That is not a valid specialization for your template.
The reason why is because std::pair<T, M> is a full specialization of the class template std::pair and therefore a class. Your template expects a class template parameter which is exactly what the compiler is telling you.

Deduce template parameter's template parameter

There is a class template A, which is taking template class for its template parameter.
template <typename T> class A {}
template <typename T> class B {}
int main()
{
A<B<int>>();
return 0;
}
Can class template A deduces its template parameter(B int)'s template parameter(int)?
Or is there the other way to solve this problem? For example,
template <typename T<typename U>> class A {}
You can make A a template template:
template <template <typename> class T, typename Inner>
class A<T<Inner>> {};
template<class>struct inner{};
template<template<class...>class Z, class T, class...Ts>
struct inner<Z<T, Ts...>>{
using type=T;
};
template<class Z>
using inner_t=typename inner<Z>::type;
and inner_t<X> is the first template argument of X if it exists, and a substitution failure otherwise.
What you described is a template template:
template< template<typename> class T > class A {};
note the class before T has to be class, not typename.

How to specialize a given template for a template

Is it possible to specialize this template for any basic_string's?
template<class T> struct X {};
Since basic_string is a template itself, I know this would be a solution:
template <template <class, class, class> class T> struct X {}; template <> struct X<basic_string> {};
However, I would like to know if the language allows to preserve the first template definition, by specializing it somehow for basic_string's only.
Yes:
#include <string>
template <typename> struct X;
template <typename TChar, typename TTraits, typename TAlloc>
struct X<std::basic_string<TChar, TTraits, TAlloc>>
{
// ...
};
Your primary template takes one type parameter, so every specialization must supply one type parameter for X, one way or another.

understanding the definition of policy-based template

template <
typename T,
template <class> class OwnershipPolicy = RefCounted, #1
class ConversionPolicy = DisallowConversion, #2
template <class> class CheckingPolicy = AssertCheck,
template <class> class StoragePolicy = DefaultSPStorage
>
class SmartPtr;
Q1> What is the syntax for the line #1
template <class> class OwnershipPolicy = RefCounted,
why it doesn't provide a parameter such as follows?
template <class T2> class OwnershipPolicy = RefCounted,
Q2> What is the difference between #1 and #2?
template <class> class OwnershipPolicy = RefCounted,
class ConversionPolicy = DisallowConversion,
Why one of these line have template<class> and the other doesn't?
template <class> class OwnershipPolicy is a template template argument. I.e. OwnershipPolicy is expected to be a template taking one (and only one) type argument. There's no name for that argument, because it's not needed, and you wouldn't be able to use it for anything anyway.
class ConversionPolicy is equivalent to typename ConversionPolicy, i.e. any ordinary type argument.
The difference lies in how you use it. For template template arguments, you provide only name of the template, which you can later use to instantiate concrete types. For typename, you need a concrete type:
template <typename A, template <typename> class B>
struct foo {};
template <typename T>
struct x {};
struct y {};
template <typename T, typename U>
struct z {};
// both of these are valid:
foo<x<int>, x> a;
foo<y, x> b;
// these are not:
foo<y, x<int>> c;
foo<y, y> d;
foo<y, z> e; // z has two template arguments, B must have only one
Worth noting that this idiom is called "policy-based design".

C++ template partial specialization

I cant figure out how to specialize partially this template. compiler complains that template parameter N is not used in partial specialization
#include <boost/multi_array.hpp>
template<typename T, class A>
struct adaptable;
template<typename T, size_t N>
struct adaptable<T,
// line below is the problem
typename boost::multi_array<T,N>::template array_view<2>::type>
{
typedef typename boost::multi_array<T,N>::template array_view<2>::type type;
};
I can add dummy template parameter just to silence compiler.
template<typename T, class A, class A0 = A>
struct adaptable;
template<typename T, size_t N>
struct adaptable<T,
typename boost::multi_array<T,N>::template array_view<2>::type,
boost::multi_array<T,N> >
{
typedef typename boost::multi_array<T,N>::template array_view<2>::type type;
};
is there more straightforward way?
I don't see anything in your example that looks like partial specialization. A partial specialization is a specialization that specifies exact types for some if the base template parameters, but leaves others open. For example:
template <class T, class U>
struct my_template {
// the base template where both T and U are generic
};
template <class T>
struct my_template<int> {
// A partial specialization where T is still generic, but U == int
};
To support partial specialization, the base template has to have at least two template parameters (call the number N). The partially specialized template can have 1..N-1 template parameters. The partial specialization must be located where the compiler will already have "seen" the base template before attempting to compile the partial specialization. The partial specialization is written as a completely separate template from the base template (though the base template and all specializations must have the same name, of course).