Для специализаций шаблонов функций вы можете явно перечислить аргументы шаблона, но это не обязательно, если выводятся аргументы шаблона.Если вы не укажете аргументы шаблона, они будут выведены компилятором с использованием тех же правил, что и при разрешении перегрузки.Чтобы решить, какую перегрузку функции следует выбрать, компилятор начинает с просмотра только первичных шаблонов (которые выбираются каким-то магическим процессом в первую очередь).Если посмотреть на два доступных основных шаблона
template <typename T> void foo(T);
template <typename T> void foo(T*);
, последний лучше подходит для аргумента указателя.Как только правильный первичный шаблон найден, компилятор ищет потенциальные специализации этого первичного шаблона.Однако ваш пример № 2 на самом деле не является специализацией шаблона функции, принимающего аргумент указателя, хотя он включает аргумент указателя.Если вы берете основное объявление
template <typename T> void foo(T*);
и заменяете T
явно указанным аргументом шаблона int*
, вы получаете
template <> void foo<int*>(int**);
То есть объявление
template <> void foo<int*>(int*);
это что-то другое.Вы, вероятно, просто хотите потерять указатель при указании аргумента шаблона:
template <> void foo<int>(int*);