Это всегда было законным C++.
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;
}
Это имеет смысл, так как шаблон по-прежнему может использоваться других специализаций или путем прямого использования угловых скобок <
>
. Поэтому перегрузка шаблона функции с помощью функции без шаблона похожа на добавление явной специализации, но с меньшим количеством головных болей.
Woah, последнее еще интереснее - будет помнить об этом, спасибо! –