См. C ++ 17 [temp.friend] / 1:
Другом класса или шаблона класса может быть шаблон функции или шаблон класса, специализация шаблона функции или класса. шаблон или нешаблонная функция или класс. Для объявления функции друга, которая не является объявлением шаблона:
- , если имя друга является квалифицированным или неквалифицированным template-id , объявление друга относится к специализации шаблон функции, в противном случае
- , если имя друга - квалифицированный-идентификатор и соответствующая нешаблонная функция найдена в указанном классе или пространстве имен, объявление друга относится к эта функция, в противном случае
- , если имя друга - это квалифицированный-идентификатор и соответствующий шаблон функции найден в указанном классе или пространстве имен, объявление друга относится к выведенной специализации этого шаблона функции (17.8.2.6), в противном случае
- имя должно быть unqualified-id , которое объявляет (или повторно объявляет) нешаблонную функцию.
Имена bar<T>
и bar<>
- это идентификатор шаблона s, поэтому, если вы используете любой из них, это относится к специализации функции. n шаблон ::bar
. Как указано в [temp.arg.explicit]:
Аргументы шаблона могут быть указаны при ссылке на специализацию шаблона функции путем уточнения имени шаблона функции списком аргументов шаблона ... Список аргументов шаблона может быть указан при ссылке на специализацию шаблона функции ... в объявлении друга. Завершающие аргументы шаблона, которые могут быть выведены (17.8.2) или получены из аргументов-шаблонов по умолчанию, могут быть исключены из списка явных аргументов-шаблонов . ... Если все аргументы шаблона можно вывести, все они могут быть опущены; ...
Таким образом, значение bar<>
в объявлении друга состоит в том, что вывод аргументов шаблона должен выполняться, чтобы определить, на какую специализацию bar
делается ссылка. Конечно, выведенная специализация - это та, которая принимает аргумент типа Foo<T>
. Таким образом, два объявления с bar<>
и bar<T>
будут иметь одно и то же значение.