The issue is not with gcc but with Visual Studio, which accepts code that is not conform to the C++ standard.
It's been answered through and through on this very site so I'll be brief.
The standard requires templates to be evaluated twice:
- once at the point of definition:
template <class T> struct Foo { void bar(); };
- once at the point of instanciation:
Foo<int> myFoo;
The first time, all the non-dependent names shall be deductible from the context:
- the compiler will throw up if you forgot punctuation, refers to unknown types/methods/attributes
- the compiler will select the overload for the functions involved at this point
Because C++ syntax is ambiguous, it is necessary to help the parser in this phase, and use the template
and typename
keywords appropriately to disambiguate manually.
Unfortunately, Visual Studio is not compliant, and only implement the second evaluation (at the point of instanciation). The advantage for the lazy is that you can get away without those extra template
and typename
keywords, the disadvantage is that your code is ill-formed and not portable...
Now for the fun part:
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;
}
Compiled with gcc, it outputs int
.
Compiled with Visual Studio, it outputs double
.
The issue ? Anyone reusing the same symbol you do in your template code in VS might step on your foot an mess up your implementation if their symbol appear between the inclusion of your template code and the moment they actually use the template code... isn't it funny :/ ?
Now, for your code:
template<typename T>
class Derived : public Base<T>
{
public:
void foo() { this->t = 4; this->get(); }
};
The this
indicates that the name following is a dependent name, ie it depends on T
(which is not obvious when the symbol appears alone). The compiler will therefore wait for the instanciation and see if for the particular type you instantiate the template Base<T>
does contain those methods. It's not mandatory, since I could perfectly specialize Base
:
// It's non-sensical to instanciate a void value,
template <>
class Base<void> {};
And thus Derived<void>
should not compile ;)