I have a problem with class member function templates. It seems that gcc is trying to analyze the code semantically too early, without explicit template instantiation.
Let the code speak
A.h (the base class):
#ifndef __A_H__
#define __A_H__
class A {
public:
A* ptr;
template<class T>
void method() {
((B*) ptr)->invoke();
}
};
#endif
B.h (the ancestor):
#ifndef __B_H__
#define __B_H__
#include<cstdio>
class B : public A {
public:
void invoke() {
printf("Method invoked\n");
}
};
#endif
main.cpp:
#include"A.h"
#include"B.h"
int main() {
A a;
a.ptr = new B();
a.method<int>();
}
This code compiles and runs fine in Visual Studio 2010 and fails to compile with following error on gcc 4.5:
In file included from main.cpp:1:0: A.h: In member function ‘void
A::method()’: A.h:10:5: error: ‘B’ was not declared in this scope
A.h:10:7: error: expected primary-expression before ‘)’ token
A.h:10:9: error: expected ‘)’ before ‘ptr’
Why is gcc trying to compile code of A::method<>() before any instantiation is requested? Which compiler behaves according to the standard?
UPDATE: Now I know that Visual Studio behaves incorrectly. B is not template parameter dependant, so it’s not looked up at instantiation, but during parsing of A.h. (relevant gcc doc)
The code incorrectly compiles in Visual Studio due to the way templates are processed (basically they are ignored until they get instantiated). In your code, the identifier
Bis not dependent on the template arguments (T) and as such, it must be available in the context where the template is defined.As
Binherits fromA, that makes everything even more complicated, as you have a cyclic dependency in the code. I would reconsider the design, and if you consider that it needs to be so, I would merge the two header files into a single one:Still, my advice would be to reconsider whether that relantionship makes sense at all, as
methodimposes the restriction thatptrmust be aB, and that rings some bells of code smell.