Reputation: 308
I have a problem with a template class and inheritance that I can't figure out. Here are the used class.
An interface template class with a typedef:
template < const unsigned long Number >
class IA
{
protected:
typedef TemplateVector<Item*, Number > List; //template array
public:
virtual List* getList() = 0;
};
The real class with same typedef (.hpp):
template < unsigned long Number >
class A : public IA< Number >
{
typedef typename IA< Number >::List List;
public:
virtual List* getList();
private:
List* m_list;
};
#include "A.cpp"
The real class with same typedef (.cpp):
template < unsigned long Number >
TemplateVector<Item*, Number >* A< Number >::getList()
{
return m_list;
}
The problem is with the .cpp definition of the getList()
function.
It causes an error when compiling and I don't know why. The error is
declaration is incompatible with "A<Number>::List *A<Number>::getList()
If I change:
typedef typename IA< Number >::List List
to
typedef TemplateVector<Item*, Number > List
it works fine but it's a redefinition and I want to avoid this kind of warning. (Note that I need to separate into .hpp and .cpp files and I use integrity compiler)
Upvotes: 1
Views: 72
Reputation: 9997
I think I understand the rationale for this happening. Consider a simpler example demonstrating the same problem
template<class T>
struct base {
typedef int foo;
};
/*
struct other{};
template<>
struct base<float> {
typedef other foo;
};
*/
template<class T>
struct test {
static typename base<T>::foo bar();
};
template<class T>
int test<T>::bar() { // (1)
return 2;
}
This produces the following error with gcc:
a.cpp:22:5: error: prototype for ‘int test<T>::bar()’ does not match any in class ‘test<T>’
int test<T>::bar() {
^
a.cpp:18:34: error: candidate is: static typename base<T>::foo test<T>::bar()
static typename base<T>::foo bar();
^
Why does this happen? Consider what the compiler would think when it encounters the line (1). Even although no template instantiation is in progress (and therefore the compiler has nothing to substitute for T
), it may try to match the header of function definition to its declaration. It sees that in the definition the return type is int
, while in the declaration the return type is typename base<T>::foo
. How can the compiler know that they will be the same type for all T
s?
Obviously the compiler can not infer this, because it is simply not true. Indeed, if you uncomment the commented part, you will find that for T=float
the base<T>::foo
will be other
, not int
.
So when the compiler hits the line (1), it can never be sure that for each T
the base<T>::foo
will be int
. (In fact, for some T
s the base<T>
can have no foo
member at all.) So if a compiler tries to check the return type before actual instantiation, it has no other way but fail.
I'm not quite good at the standard, so I can not support this explanation by the quotes from there; maybe I'm in fact wrong and there is another reason based on the standard.
And anyway, as I noted in the comment, you should not use StaticInternalVersatileVector<Item*, Number >*
as a return type at all. The simplest and the most correct way is to use just typename A<Number>::List*
.
Upvotes: 2