2016-11-29 4 views
3

Допустим, у меня есть шаблон функции:функция Declare после шаблона определяется

template <class T> 
void tfoo(T t) 
{ 
    foo(t); 
} 

позже я хочу использовать его с типом, поэтому я объявляю/определить функцию и попытаться назвать:

void foo(int); 

int main() 
{ 
    tfoo(1); 
} 

, и я получаю сообщение об ошибке с г ++:

«Foo» не был объявлен в этой области, и никакие декларации не были найдены аргументом в зависимости от поиска в момент создания [-fpermissive] foo (t);

Почему он не может найти void foo(int) в момент создания объекта? Об этом говорится в этом пункте. Есть ли способ заставить его работать (без перемещения объявления foo перед шаблоном)?

+0

не так, потому что [двухэтапный поиск] (http://stackoverflow.com/questions/7767626/two-phase-lookup-explanation-needed)? –

+0

@ W.F. на самом деле я бы ожидал, что это скомпилируется из-за двухфазного поиска. – Slava

+2

Возможно, объявление функции, которую вы хотите вызвать внутри шаблона функции, решит проблему для вас? – SirGuy

ответ

8

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 и завершается успешно.


Это довольно распространенное заблуждение, когда люди считают, что вторая фаза так называемым «двухфазного поиск» должна быть в состоянии видеть все что дополнительно заявленной ниже определения шаблона вплоть до точка инстанцирования (точка вызова в этом случае).

Нет, вторая фаза не видит ничего. Он может видеть дополнительный материал только в пространствах имен, связанных с аргументами функции. Все остальные пространства имен не обновляются. Они видны, как если бы они наблюдались с точки зрения определения шаблона.

+0

Если я изменяю тип 'T' как некоторый класс, то не должно появляться пространство имен этого класса? [это не так) (http://coliru.stacked-crooked.com/a/19f9b4a7c8b9f0c0) Поэтому я явно не понимаю чего-то. Только если 'foo' принимает зависимый тип, похоже, он также должен быть внесен. – AndyG

+0

@AndyG: Должно. Как я уже говорил выше, типы классов имеют * связанные пространства имен *. Фундаментальные типы (например, 'int') не имеют связанных пространств имен. По этой причине зависимый поиск работает по-разному для типов классов и основных типов. – AnT

+0

@AndyG Вы вызываете 'foo' с и' int' в качестве аргумента, ADL не происходит. – vsoftco