Это, действительно, специализация шаблонов, как уже упоминалось ранее. Должен быть какой-то ранее объявленный шаблон функции, такой как:
template<typename T, typename U>
void operator>>(const T& s, const U d) {...}
Тем не менее, это довольно ошибочно. Гораздо лучше удалить template<>
, так что operator>>
будет просто перегружен. Проблема со специализацией шаблона функции заключается в том, что это может привести к неожиданному поведению при наличии перегруженных функций (а operator>>
имеет много перегрузок), поскольку специализация не перегружается. Это означает, что компилятор сначала выбирает наиболее подходящую перегрузку для функции, а затем, если выбранная перегрузка является шаблоном функции, он ищет специализации шаблона, чтобы определить, существует ли соответствующая.
Классический пример (к сожалению, я не помню, где я его читал). Рассмотрим этот перегруженный шаблон функции:
template <typename T>
void Function(T param);
template <typename T>
void Function(T* param);
template <>
void Function(int* param);
main()
{
int i = 5;
Function(&i);
}
Как и ожидалось, шаблонная специализация для int*
называется. Но просто измените порядок определения функций:
template <typename T>
void Function(T param);
template <>
void Function(int* param);
template <typename T>
void Function(T* param);
main()
{
int i = 5;
Function(&i);
}
Теперь вызывается общий шаблон для T*
, поскольку мы специализируем шаблон для T
, а не для T*
, и этот второй шаблон лучше подходит для нашего вызова. Этого можно было бы избежать, если бы мы перегрузили функцию вместо того, чтобы специализировать шаблон:
void Function(int* param);
Теперь порядок объявления не имеет значения, мы всегда будем вызывать перегрузку для int*
.
ОБНОВЛЕНИЕ: Теперь я знаю, кому кредитовать. Я читал об этом в статье Херба Саттера. Пример предоставили Петр Димов и Дейв Абрахамс.