„W 1985 roku, pierwsza edycja C++ Programming Language został wydany, które stały się ostateczne odniesienie do języka, jak nie było jeszcze oficjalnym standardem”. wiki C++ History Nie zmieniło się to między C++ 11 i C++ 14. Mogę założyć (i proszę przyjąć to z przymrużeniem oka), które zmieniło się między "standaryzacją" a standaryzacją. Może ktoś, kto wie lepiej historię C++, może rzucić więcej światła tutaj.
chodzi o to, co rzeczywiście się dzieje:
Najpierw przejdźmy się na sposób prosty:
extern g(double);
To nieważne C++. Historycznie, niestety C dozwolone pominięcie typu. W C++ musisz napisać extern void g(double)
.
Następnie zignorujmy przeciążenie g(double)
odpowiedzieć na pierwsze pytanie:
template <class T>
void f(T value)
{
g(value);
}
void g(int v);
int main()
{
f(2);
}
W C++ jest niesławny dwufazowy wyszukiwanie nazw:
- W pierwszej fazie, w definicja szablonu, wszystkie non-dependent names zostały rozwiązane. Niewykonanie tego jest trudnym błędem;
- Nazwy zależne są rozwiązywane w fazie drugiej podczas tworzenia szablonu.
Zasady są nieco bardziej skomplikowane, ale to jest sedno.
g
jest zależny od parametru szablonu T
, więc przechodzi przez pierwszą fazę. Oznacza to, że jeśli nigdy nie tworzysz instancji f
, kod kompiluje się dobrze. W drugiej fazie f
jest tworzony z T = int
. g(int)
jest teraz szukał, ale nie znaleziono:
17 : error: call to function 'g' that is neither visible in the template definition nor found by argument-dependent lookup
g(value);
^
24 : note: in instantiation of function template specialization 'f<int>' requested here
f(2);
^
20 : note: 'g' should be declared prior to the call site
void g(int v);
W porządku dla dowolnej nazwy g
zdać śpiewająco mamy kilka możliwości:
- Zadeklaruj
g
poprzednio:
void g(int);
template <class T>
void f(T value)
{
g(value);
}
- przynieśsię z
T
:
template <class T>
void f(T)
{
T::g();
}
struct X {
static void g();
};
int main()
{
X x;
f(x);
}
- Doprowadzić
g
się z T
poprzez ADL:
template <class T>
void f(T value)
{
g(value);
}
struct X {};
void g(X);
int main()
{
X x;
f(x);
}
Te oczywiście zmiany semantyki programu. Mają one ilustrować, co możesz i czego nie możesz mieć w szablonie.
Jak, dlaczego nie znaleźć g(int)
ADL, ale znajdzie g(X)
:
§ 3.4.2 Argument-dependent name lookup [basic.lookup.argdep]
For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered [...]:
If T is a fundamental type, its associated sets of namespaces and classes are both empty.
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. [...]
I wreszcie dostać się do wewnątrz dlaczego extern void g(double);
główny nie zostanie znaleziony: przede wszystkim pokazaliśmy, że g(fundamental_type)
został znaleziony iff jest zadeklarowany przed definicją f
. Zróbmy więc void g(X)
wewnątrz main
. Czy ADL ją odnajduje?
template <class T>
void f(T value)
{
g(value);
}
struct X{};
int main()
{
X x;
void g(X);
f(x);
}
Nie, ponieważ nie znajdują się w tej samej przestrzeni nazw jako X
(tj globalnej przestrzeni nazw) ADL nie może go znaleźć.
Dowód g
nie jest w globalnej
int main()
{
void g(X);
X x;
g(x); // OK
::g(x); // ERROR
}
34 : error: no member named 'g' in the global namespace; did you mean simply 'g'?
„w 1985 roku, pierwsza edycja C++ Programming Language został wydany, które stały się ostateczne odniesienie do języka, jak ** nie było jeszcze oficjalny standard **. " [wiki] (https://en.wikipedia.org/wiki/C%2B%2B#History) Tak więc nie zmieniło się pomiędzy 'C++ 11' i' C++ 14'. Zmieniło się pomiędzy "standaryzacją" a standaryzacją. – bolov
Sprawdź 14.6.4.1 [temp. Punktu] dla zasad – AndyG
szukaj również wyszukiwania z dwoma fazami – bolov