Ответ 1
Это всегда было законным С++.
14.5.6/2:
Шаблон функции может быть перегружен другими шаблонами функций и с обычными (не шаблонными) функциями. Нормальная функция не связана с шаблоном функции (т.е. Никогда не считается специализацией), даже если она имеет то же имя и тип, что и потенциально сгенерированная спецификация шаблона функций.
При использовании синтаксиса "шаблон-идентификатор", такого как add<int>
, рассматриваются только функции шаблонов с достаточным количеством параметров шаблона. Таким образом, a.add<int>()
даже не смотрит, соответствует ли не шаблон add
.
Когда идентификатор называет как обычную функцию, так и шаблон функции, компилятор попытается вывести аргументы шаблона для шаблона функции, чтобы получить специализированную функцию шаблона. Затем все простые функции и все специализированные функции шаблонов сравниваются с обычной логикой перегрузки функции. [См. 13.3.1/7.]
В вашем примере вызов a.add()
не может вывести аргумент шаблона T
для версии шаблона. Таким образом, единственной жизнеспособной функцией является перегрузка без шаблонов.
Также существует другое правило, которое возникает в аналогичной ситуации: если функция без шаблона и специализированная функция шаблона в противном случае были бы неоднозначной перегрузкой, выигрывает функция без шаблона. [Это правило находится в разделе 13.3.3, в середине определения того, что делает одну функцию лучше другой для заданного набора аргументов.]
class B
{
public:
int f(int n) { return n+1; }
template<typename T>
T f(T n) { return n; }
};
int main() {
B b;
b.f(1); // both are viable, non-template wins
b.f<int>(1); // only the template is viable
return 0;
}
Это имеет смысл, потому что шаблон все еще может использоваться другими специализациями или явно используя угловые скобки <
>
. Поэтому перегрузка шаблона функции с помощью функции без шаблона похожа на добавление явной специализации, но с меньшим количеством головных болей.