Меня смущает вопрос о создании экземпляра со следующим примером:
#include <iostream>
void f(int){std::cout<<"int"<<std::endl;}//3
template <typename T>
void g(T t)
{
f(t);//4
}
void f(double){std::cout<<"double"<<std::endl;}
int main()
{
g<int>(1);//1.point of instantiation for g<int>
g<double>(1.1);//2.point of instantiation for g<double>, so f(double) is visible from here?
return 0;
}
Я, хотя f является зависимым именем и 1. является точкой создания для g< int> и 2. является точкой создания для g< double>, поэтому f (double) видна для g (1.1), однако вывод
int
int
и если я прокомментирую объявление f (int) в 3, gcc сообщает об ошибке (не удивительно) и указывает, что f (t) в 4 является точкой создания экземпляра (удивленный !!).
test.cpp: In instantiation of ‘void g(T) [with T = int]’:
test.cpp:16:10: required from here
test.cpp:9:5: error: ‘f’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
f(t);
^
Кто-нибудь может прояснить для меня понятие точки инстанцирования и связывания имени?
f(t)
является зависимым неквалифицированным выражением вызова функции, поэтому кандидатами являются только функции, найденные в контексте определения, и функции, найденные через ADL. f(int)
виден в контексте определения, но не f(double)
поэтому разрешение перегрузки разрешается до f(int)
для обоих звонков.
f(double)
не может быть найден ADL, потому что встроенные типы не имеют связанных классов или пространств имен. Если вы передали аргумент типа класса, и произошла перегрузка f
Принимая этот тип, ADL сможет найти его. Например:
void f(int);
template <typename T>
void g(T t)
{
f(t);
}
class A {};
void f(double);
void f(A);
int main()
{
g(1); // calls f(int)
g(1.1); // calls f(int)
g(A{}); // calls f(A)
}
f(A)
вызывается, потому что он расположен в глобальном пространстве имен, и A
Связанный набор пространств имен является глобальным пространством имен.