Ответ
Частичная специализация шаблона — это механизм C++, позволяющий предоставить отдельную, более специфичную реализацию шаблона класса для определенного подмножества его возможных аргументов, при этом оставляя некоторые параметры шаблона все еще обобщенными. Важно: частичная специализация применима только к шаблонам классов (включая struct и union), но не к шаблонам функций.
Зачем это нужно? Для оптимизации, предоставления особого интерфейса или изменения поведения шаблона для конкретных категорий типов (например, для указателей, для массивов, когда оба типа одинаковы).
Пример: оптимизированный Container для типа bool:
// 1. Основной (первичный) шаблон класса
template<typename T, std::size_t Size>
struct Container {
T data[Size];
void fill(const T& value) {
std::fill(std::begin(data), std::end(data), value);
}
// ... другие методы
};
// 2. Частичная специализация для типа bool.
// Мы специализируем параметр T (делаем его конкретным - bool),
// но оставляем параметр Size обобщенным.
template<std::size_t Size>
struct Container<bool, Size> {
// Для хранения булевых значений эффективнее использовать bitset
std::bitset<Size> bits;
void fill(bool value) {
bits = value ? ~std::bitset<Size>{} : std::bitset<Size>{};
}
// Можем добавить специфичные для bool методы
bool test(std::size_t pos) const { return bits.test(pos); }
};
// Использование
int main() {
Container<int, 10> intContainer; // Использует основной шаблон (массив int[10])
Container<bool, 20> boolContainer; // Использует частичную специализацию (std::bitset<20>)
boolContainer.fill(true);
std::cout << boolContainer.test(5); // Работает метод из специализации
}
Другой распространенный пример: специализация для указателей
template<typename T>
struct PtrTraits {
static const char* name() { return "Value Type"; }
};
// Частичная специализация для всех типов указателей T*
template<typename T>
struct PtrTraits<T*> {
static const char* name() { return "Pointer Type"; }
};
// Использование
PtrTraits<int>::name(); // "Value Type"
PtrTraits<double*>::name(); // "Pointer Type"
PtrTraits<std::string*>::name(); // "Pointer Type"
Критические правила:
- Список аргументов частичной специализации должен быть менее обобщенным, чем у первичного шаблона, но не полностью конкретным (иначе это будет полная специализация).
- Количество параметров в специализации может отличаться от первичного шаблона, но должно соответствовать логике "частичной" спецификации.
- Компилятор всегда выбирает наиболее специализированную подходящую версию шаблона.