Zauważyłem, że po uzyskaniu dostępu do atrybutu innego niż szablon (v.foo
) ze zmiennej typu szablonu (T& v
), C++ można nabrać na myślenie, że jest to szablon elementu, jeśli istnieje jest funkcją szablonu o tej samej nazwie (template class <T> void foo()
). Jak to wyjaśnić w specyfikacji C++? Rozważmy ten prosty program:C++ mylące nazwa atrybutu dla szablonu członkowskiego
#include <cassert>
/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
return v.foo < 0;
}
struct X
{
int foo;
};
int main()
{
X x;
x.foo = 5;
assert(!foo_negative(x));
return 0;
}
mamy funkcję szablonu foo_negative
że trwa obiekt dowolnego typu i określa, czy jego atrybut foo jest ujemna. Funkcja main
tworzy instancję foo_negative
z [T = X]. Ten program kompiluje i działa bez żadnych danych wyjściowych.
Teraz dodać tę funkcję do górnej części programu:
template <class T>
void foo()
{
}
kompilowanie go z G ++ 4.6.3 powoduje ten błąd kompilatora:
funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5: instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function
(Gdzie Linia 13 jest return v.foo < 0
i Linia 25 to assert(!foo_negative(x))
.)
Klang powoduje podobne błędy.
Wat? W jaki sposób dodanie niepowiązanej funkcji, która nigdy nie jest nazywana, powoduje wprowadzenie błędu składni do poprawnego programu? Podczas analizowania foo_negative
kompilator nie zna typu v
i, co najważniejsze, nie wie, czy v.foo
jest szablonem członka, czy zwykłym członkiem. Najwyraźniej musi zdecydować w czasie analizowania (zanim szablon zostanie utworzony), czy traktować go jako szablon członkowski czy zwykłego członka.
Jeśli uzna v.foo
szablon jest członkiem, a następnie < 0
jest postrzegany jako uboczny 0
jako szablonu argumentu, i jest tam brakuje >
, stąd błąd składni. Następnie, gdy foo_negative
jest tworzone z [T = X], pojawia się kolejny błąd, ponieważ X::foo
nie jest szablonem członkowskim.
Ale dlaczego uważasz, że v.foo
jest szablonem członka? Ta niejednoznaczność jest właśnie tym słowem kluczowym template
: jeśli napisałem v.template foo
, to wyraźnie powiedziałbym C++, aby oczekiwał szablonu członkowskiego, ale nie użyłem słowa kluczowego template
! Nie odwoływałem się do szablonu członkowskiego, więc należy założyć, że jest to zwykły członek. Fakt, że istnieje funkcja o tej samej nazwie co członek, nie powinien mieć żadnego efektu. Dlaczego to robi? Nie może to być błąd w kompilatorze, ponieważ GCC i clang są spójne.
To dziwne. Kompiluje on na gcc-4.3.4: http://ideone.com/FP3SO –
Nie, zapomniałeś dodać 'template void foo()' declaration: http://ideone.com/FxEBm Nie kompiluje . –
mgiuca
być może jest to błąd zarówno w gcc jak i clang: [declaration] (http://ideone.com/zofCF). Zmieniłem 'v.foo < 0' to '0 > v.foo' i kompiluje się dobrze. Być może oba kompilatory uważają, że '<0' jest argumentem szablonu, o czym wspomniałeś w pytaniu. – user2k5