Reputation: 466
//A.h
template <class T>
class A
{
public:
typename T::Type x; //(1) compile time error: C2039 'Type': is not a member of 'B'
void f();
};
template <class T>
void A<T>::f()
{
typename T::Type x1; //(2) but no errors here
}
//B.h
#include "A.h"
class B : public A<B>
{
public:
using Type = int;
};
//main.cpp
#include "B.h"
int main()
{
B x;
}
Why there is error in (1) but no errors in (2)?
How can I store a variable of type typename T::Type
and write function like func(typename T::Type)
in A class?
I don't know why this class design was done and I don't want to change class hierarchy or template parameters in code because there are a lot of classes inherited from A and code is quite confusing. So please no advices in this way.
P.S. Sorry for not clear question name, but I cannot invent better one.
Upvotes: 0
Views: 73
Reputation: 66371
You can't do that due to circularity in definitions - A<B>
can't be defined until B
is defined, and B
can't be defined until A<B>
is defined.
What you can do is add a level of indirection, going through a "traits" class that's independent of the ultimate definition of B
.
Example:
template <typename T>
struct traits{};
template <class T>
class A
{
public:
typename traits<T>::Type x;
};
class B;
template <>
struct traits<B>
{
using Type = int;
};
class B : public A<B>
{
public:
using Type = typename traits<B>::Type;
};
int main()
{
B x;
}
Upvotes: 0
Reputation: 25603
While you are define class B : public A<B>
the class B
is not defined but you try to use this class in A. At this point of time, the compiler has no knowledge if there will be a definition of using Type = int;
.
gcc provides a more readable error message: "invalid use of incomplete type 'class B'"
void A<T>::f()
will never be instantiated, so you will not see an error message.
The bad news: You have no chance to do any kind of forward declaration in this situation as you have a full circular dependency.
Upvotes: 3
Reputation: 119857
class B : public A<B>
B
is incomplete at this point. It is not known yet that it has a Type
member. So instantiation of A::x
fails.
By contrast, A<T>::f()
is never instantiated. If you do instantiate it, it is likely to happen when B
is a complete type, so B::Type
should already be known.
Upvotes: 1