foo
в вашем случае является зависимым именем , так как выбор функции зависит от типа, если аргумент и тип аргумента зависят от параметра шаблона. Это означает, что foo
просматривается в соответствии с правилами зависимым поиском.
Разница между зависимой и не зависимым от поиска является то, что в случае зависимого поиска ADL-номинированных пространства имен рассматриваются как продлено: они вытянуты с дополнительными именами, видимыми с точкой шаблона конкретизации (tfoo
звонок в вашем случае). Это включает имена, которые появились после объявления шаблона. Ключевым моментом здесь является то, что только Расширения, назначенные ADL, расширяются таким образом.
(По ADL назначенных имен Я имею в пространство имен , связанный с функции типа аргумента и, следовательно, привести в рассмотрение правил зависимого поиска имен см. «3.4.2 Аргумент-зависимый поиск имени»)
В вашем случае аргумент имеет тип int
. int
- это фундаментальный тип. Фундаментальные типы не имеют связанных пространств имен (см. «3.4.2 Поиск зависимых от аргументов имен»), что означает, что он не назначает какое-либо пространство имен через ADL. В вашем примере ADL вообще не участвует. Поиск зависимого имени для foo
в этом случае ничем не отличается от не зависящего от поиска. Он не сможет найти ваш foo
, так как он объявлен ниже шаблона.
Обратите внимание на разницу в следующем примере
template <class T> void tfoo(T t)
{
foo(t);
}
struct S {};
void foo(S s) {}
int main()
{
S s;
tfoo(s);
}
Этот код будет компилироваться, так как аргумент типа S
является типом класса. Он имеет связанное пространство имен - глобальное - и добавляет (назначает) это глобальное пространство имен для зависимого поиска имени. Такие пространства имен, назначенные ADL, просматриваются зависимым поиском в обновленной форме (как видно из точки вызова). Вот почему поиск может видеть foo
и завершается успешно.
Это довольно распространенное заблуждение, когда люди считают, что вторая фаза так называемым «двухфазного поиск» должна быть в состоянии видеть все что дополнительно заявленной ниже определения шаблона вплоть до точка инстанцирования (точка вызова в этом случае).
Нет, вторая фаза не видит ничего. Он может видеть дополнительный материал только в пространствах имен, связанных с аргументами функции. Все остальные пространства имен не обновляются. Они видны, как если бы они наблюдались с точки зрения определения шаблона.
не так, потому что [двухэтапный поиск] (http://stackoverflow.com/questions/7767626/two-phase-lookup-explanation-needed)? –
@ W.F. на самом деле я бы ожидал, что это скомпилируется из-за двухфазного поиска. – Slava
Возможно, объявление функции, которую вы хотите вызвать внутри шаблона функции, решит проблему для вас? – SirGuy