Problem nie dotyczy gcc, ale Visual Studio, w hich akceptuje kod, który nie jest zgodny ze standardem C++.
Została udzielona odpowiedź na tej stronie, więc będę krótko.
Standard wymaga szablonów być oceniane dwukrotnie:
- raz w punkcie definicji:
template <class T> struct Foo { void bar(); };
- raz w punkcie instanciation:
Foo<int> myFoo;
po raz pierwszy, wszyscy nazwy niepowiązane podlegają odliczeniu od kontekstu:
- kompilator będzie rzucać się jeśli zapomniałeś interpunkcyjnych, odnosi się do nieznanych typów/metod/atrybuty
- kompilator wybrać przeciążenie dla funkcji zaangażowanych w tym momencie
Ponieważ C składnia ++ jest niejednoznaczna, konieczne jest aby pomóc parserowi w tej fazie, i odpowiednio użyć słów kluczowych template
i typename
do dwuznaczności.
Niestety program Visual Studio nie jest zgodny i wdraża tylko drugą ocenę (w miejscu instancji).Korzyścią dla leniwych jest to, że można uciec bez tych dodatkowych template
i typename
słów kluczowych, wadą jest to, że kod jest źle sformułowane i nie przenośny ...
Teraz część zabawy:
void foo(int) { std::cout << "int" << std::endl; }
template <class T> void tfoo(T i) { foo(i); }
void foo(double) { std::cout << "double" << std::endl; }
int main(int argc, char* argv[])
{
double myDouble = 0.0;
tfoo(myDouble);
return 0;
}
Skompilowana z gcc, wyprowadza int
.
Skompilowany za pomocą Visual Studio, wyprowadza double
.
Problem? Każdy, kto ponownie użyje tego samego symbolu, co w kodzie szablonu w VS, może stanąć na wysokości zadania, jeśli jego symbol pojawi się pomiędzy włączeniem twojego kodu szablonu a chwilą, w której faktycznie używają kodu szablonu ... czyż nie jest to prawda? zabawny :/ ?
Teraz dla kodu:
template<typename T>
class Derived : public Base<T>
{
public:
void foo() { this->t = 4; this->get(); }
};
this
wskazuje, że nazwa jest zależna od następujących nazwa, to znaczy zależy T
(co nie jest oczywiste, kiedy pojawi się symbol spokoju). Kompilator będzie więc oczekiwał na instancję i zobacz, czy dla konkretnego typu, który utworzysz, szablon Base<T>
zawiera te metody. To nie jest obowiązkowe, ponieważ mogłem doskonale Specjalizujemy Base
:
// It's non-sensical to instanciate a void value,
template <>
class Base<void> {};
I tak Derived<void>
nie powinien skompilować;)
Obowiązkowa Link do C++ FAQ: http://www.parashift.com/c++-faq- lite/templates.html # faq-35.19 – UncleBens
Krótka odpowiedź: ponieważ gcc jest zgodny ze standardami i (co zaskakujące) Visual C++ nie jest? –