Специализация используется. traits<foo*>::const_reference
- это const foo
. Если вы хотите, чтобы это был указатель, используйте:
template<typename T>
struct traits<T*>
{
typedef const T* const_reference;
};
При этом traits<foo*>::const_reference
будет const foo*
.
Обратите внимание, что использование T
в специализации traits<T*>
полностью отделено от T в шаблоне traits
. Вы можете переименовать его:
template<typename U>
struct traits<U*>
{
typedef const U* const_reference;
};
и у вас будет та же специализация. Это имеет больше смысла, если у вас есть опыт в функциональном программировании.
Для начала представьте, что template <typename ...>
представляет абстракцию, а не функция, абстрагирующая значение. Это как поворот
sum = 0
for item in [1,2,3]:
sum += item
в:
function sum(l):
sum = 0
for item in l:
sum += item
return sum
, где l
занимает место [1,2,3]
. Мы можем вызвать sums
из другой функции, которая сама имеет формальный параметр с именем l
:
function sumsq(l):
return sum(map(lambda x: x*x, l))
1034 * "l" не имеет ничего общего с sum
"l".
С помощью шаблонов мы абстрагируем имена типов, а не значения. То есть мы переходим:
struct traits {
typedef const double& const_reference;
};
в
template <typename T>
struct traits {
typedef const T& const_reference;
};
Теперь рассмотрим не шаблонную специализацию:
template <>
struct traits<double*> {
typedef const double* const_reference;
};
Здесь нет параметров шаблона для специализации, но вы можете думать о traits<double*>
как о применении шаблона traits
к double*
. Извлеките double
и получите:
template <typename T>
struct traits<T*> {
typedef const T* const_reference;
};
Здесь T
- это параметр для специализации, а не базовый шаблон.