Специализировать шаблон с шаблоном - PullRequest
3 голосов
/ 03 марта 2012

У меня есть (бесплатный) шаблон функции, который выглядит так

template <typename T>
T get();

Теперь я хочу специализировать эту функцию для класса, который сам является шаблоном. Но мой компилятор не хочет его компилировать, и сейчас я спрашиваю, возможно ли это, и как мне этого добиться. Просто для идеи, код может выглядеть следующим образом: (не компилируется)

template <>
template <typename T>
foo_type<T> get<foo_type<T>>()

Ответы [ 2 ]

4 голосов
/ 03 марта 2012

То, что вы делаете, называется частичная специализация шаблона функции.Но частичная специализация шаблона функции не допускается.Перегрузка шаблона функции разрешена, но в этом случае это также невозможно, поскольку функция имеет только тип возвращаемого значения, а перегрузка по типу возвращаемого значения не допускается.

Таким образом, решение таково:

namespace details
{
     template <typename T>
     struct worker
     {
         static T get();
     };

     template <typename T> //partial specialization of class is allowed
     struct worker<foo<T>>
     {
         static foo<T> get();
     };

}

template <typename T>
T get()
{
  return details::worker<T>::get();
}

Вы также можете использовать перегрузки, если вы определите, что они принимают один аргумент, чтобы сделать перегрузку действительной:

namespace details
{
     template <typename T>
     static T get(T*); 

     template <typename T> 
     static foo<T> get(foo<T>*); //now the overload is valid

}

template <typename T>
T get()
{
  return details::get<T>(static_cast<T*>(0));
}

Обратите внимание, что аргумент static_cast<T*>(0) используется, чтобы помочькомпилятор для выбора правильной перегрузки.Если T отличается от foo<U>, тогда будет выбрана первая перегрузка, поскольку тип передаваемого ей аргумента будет T*, а не foo<U>*.Если T равно foo<U>, то компилятор выберет вторую перегрузку, поскольку она more специализирована и может принять переданный ей аргумент, который в данном случае равен foo<U>*.

2 голосов
/ 03 марта 2012

Как сказал Наваз, стандарт просто не позволяет вам этого делать.Однако вы можете извлечь реализацию в статический метод класса и частично специализировать этот класс.

template<class T>
struct get_impl{
  static T get(){ ... }
};

template<class T>
struct get_impl<foo_type<T> >{
  static foo_type<T> get(){ ... }
};

template<class T>
T get(){ return get_impl<T>::get(); }
...