Второй void foo(...
- это перегрузка (а не специализация), которая не видна при определении foo_fun::fun
, поэтому она не будет найдена в контексте определения шаблона. Поскольку T*
является зависимым типом, разрешение foo
в выражении foo((T*)0, 0)
будет отложено до времени создания шаблона и также будет учитываться контекст создания. Однако 14.6.4.2 стандарта гласит, что если имя функции является unqualified-id , но не template-id , то для функций поиска без ADL только функции, видимые в точке Определение шаблона рассматриваются. В пространстве имен Foo
отсутствуют аргументы функций, поэтому поиск в зависимости от аргументов не происходит, поэтому вызывается версия шаблона foo
, а не перегрузка без шаблона.
Большое спасибо litb за исправления к этому ответу.
Если вы сделали его специализацией, как показано ниже, то, поскольку специализации выбираются во время создания шаблона, специализация может быть вызвана, если соответствующая специализация видна в точке, в которой шаблон функции создается впервые для int
.
namespace Foo {
template<>
void foo<int>(int *, int) { puts("int"); }
}
Глава 14 действующего стандарта, но она не очень читаема:)
Редактировать: Если бы мне пришлось выбирать наиболее релевантную часть стандарта, это, вероятно, было бы 14.6 [temp.res], параграф 9. (Немного сокращено) Если имя не зависит от шаблона-параметра объявление для этого имени должно находиться в области действия в том месте, где имя появляется в определении шаблона; имя привязано к объявлению, найденному в этой точке, и на эту привязку не влияют объявления, видимые в момент создания экземпляра.
Редактировать, редактировать: Но вам также необходимо принять во внимание 14.6.4.2 [temp.dep.candidate]. Очень сложно и опасно пытаться ссылаться на стандарт из-за всех взаимозависимостей, этот ответ является наглядным примером.