Как специализировать шаблон класса с параметром шаблона?

Я хотел бы специализировать шаблон класса на параметре шаблона типа параметра шаблона шаблона. Является ли это возможным? Если да, какой синтаксис?

#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

Мотивация: Давайте предположим, что параметр шаблона шаблона обозначает Коллекции (например, std::vector, std::deque). И я хочу специализироваться Z на std::vector но меня не интересует параметр шаблона типа std::vector, это нормально. Также я хочу специализироваться на всех типах Коллекции, которая содержит int,

Этот вопрос похож на следующие вопросы, но они либо пытаются специализировать шаблон функции

или они пытаются специализироваться не на параметре шаблона шаблона

или нет параметра шаблона шаблона в основном шаблоне

2 ответа

Решение

Следующий код компилируется нормально:

#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
}

В своем коде вы даете Z параметр шаблона шаблона, хотя это должно быть сделано только для специализации. Вот почему ваш код не компилируется.

Это не может работать, потому что в вашем коде:

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

Z ожидает шаблон класса в качестве параметра.

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

Здесь вы не специализируете ни один из аргументов шаблона и не пытаетесь передать C<int> который не является шаблоном класса (C является шаблоном класса и отличается от C<int> который является конкретным типом).

Если в вашем классе есть параметр шаблона, который является шаблоном класса, и вы хотите, чтобы ваш класс вел себя по-разному для разных типов, передаваемых для контейнера, вы, вероятно, должны сделать что-то вроде:

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();
    //...
};
Другие вопросы по тегам