При обращении к шаблону, имя которого зависит от параметра типа, зачем перед ним требуется ключевое слово template?
Ключевое слово template сообщает компилятору, что зависимое имя после . или -> обозначает шаблон, а следующий <...> — список его аргументов, а не операторы сравнения. Без этого указания выражение обычно разбирается синтаксически неверно или не так, как ожидается.
В шаблонах C++ часть имен зависит от параметров типа, поэтому их смысл нельзя окончательно определить до инстанцирования. При этом компилятор должен разобрать шаблон уже на первом этапе компиляции, когда конкретный тип еще неизвестен.
Такая двухфазная обработка создает неоднозначность: последовательность после зависимого имени может выглядеть как сравнение через оператор <, а может быть аргументами шаблона. Ключевое слово template устраняет эту неоднозначность.
Рассмотрим вызов метода шаблона через объект типа T. До подстановки конкретного T компилятор не знает, является ли имя метода шаблоном. Поэтому запись с угловыми скобками нельзя надежно интерпретировать без дополнительного синтаксического указания.
Если template пропустить, ошибка возникает на этапе разбора исходного шаблона, еще до проверки того, существует ли у конкретного типа нужный метод. Это отличается от ситуации, когда имя распознано как шаблон, но сам вызов впоследствии оказывается некорректным.
После зависимого квалификатора . или -> ключевое слово пишется непосредственно перед именем шаблона: объект.template имя<аргументы>(). Для зависимого квалифицированного имени типа используется аналогичная форма: T::template имя<аргументы>.
В invoke тип T зависим от параметра шаблона, поэтому object.convert<int>() требует disambiguator template. После подстановки T = Converter компилятор проверяет, что convert действительно является шаблоном и что вызов допустим.
Для неквалифицированного имени, найденного обычным поиском, это ключевое слово обычно не требуется. Также оно не нужно, если имя уже однозначно распознано как шаблон в не依сящем от параметров контексте.
Важно отличать template от typename. typename сообщает, что зависимое квалифицированное имя обозначает тип, а template — что оно обозначает шаблон. В одной конструкции они могут использоваться вместе, например при обращении к вложенному типу специализации шаблона: сначала указывается template, затем typename перед полным зависимым именем типа.
В шаблонном адаптере нужно вызвать у пользовательского типа вложенный метод-шаблон преобразования. Если разработчик записывает вызов без template, код не проходит синтаксический разбор, хотя конкретный тип действительно содержит такой метод.
Вариант с попыткой убрать шаблонность метода упрощает синтаксис, но лишает API параметризации типа результата. Вариант с явным template сохраняет общий интерфейс, однако требует от автора библиотеки понимания правил зависимых имен.
Выбранное решение — использовать disambiguator в месте вызова. Это не влияет на производительность и не создает дополнительных объектов: ключевое слово нужно только компилятору для корректного разбора и последующей инстанциации шаблона.
template при обращении через неквалифицированное имя?Нет, если имя не является зависимым квалифицированным именем и обычный поиск уже однозначно устанавливает, что оно является шаблоном. Например, вызов функции-шаблона по имени, не зависящему от параметра типа, не требует такого disambiguator.
Ключевая причина требования — не сам факт наличия <...>, а невозможность определить природу имени на этапе разбора шаблона.
template, чтобы вызов всегда стал корректным?Нет. Ключевое слово только меняет синтаксическую интерпретацию имени. После подстановки типов компилятор по-прежнему проверяет наличие шаблона, соответствие числа и видов аргументов, доступность метода и корректность самого вызова.
Поэтому template устраняет проблему разбора, но не заменяет проверку интерфейса типа и не превращает произвольное имя в существующий шаблон.
typename и template?template относится к имени вложенного шаблона, а typename — к тому, что итоговое зависимое имя является типом. Например, при обращении к типу, объявленному внутри специализации вложенного шаблона, сначала нужно разобрать имя специализации как шаблон, а затем явно указать, что результатом является тип.
Это две независимые неоднозначности: одна касается природы имени до <...>, другая — природы полного квалифицированного имени после подстановки параметров.