A function returning T <a> does not compile in a specific typedef situation
I do not understand why func3() cannot compile when func2() and func4() do.
- g ++ 4.1.2 :
error: 'B<T>::my_t' has incomplete type - VS2008:
error C2079: 'B<T>::my_t' uses undefined class 'A'
template <typename T> struct C { T mt_t; }; template <typename T> struct B { typedef C<T> C_type; T my_t; }; struct Other {}; struct A { B<A> func2(); B<A>::C_type func3(); // error: 'B<T>::my_t' has incomplete type B<Other>::C_type func4(); }; int main() {} Well, when you try to get B<A>::C_type , you need to create an instance of template <typename> B , but you cannot create an instance of a template of an incomplete type, because it contains a member object T my_t , which should not be incomplete - the compiler does not know that you want to get only the typedef member from B<A> .
In func2 you only use B<A> as the return type, which may be incomplete - we do not need to instantiate B<A> to allow it as the return type. But to access the member (typedef) we need to create an instance of B<A> . Furhtermore, func4 excellent because Other is a complete type.
The solution is simple, just enable typedef manually and make the return type func3 in C<A> .
There are several factors.
A is incomplete
First, in all function declarations:
B<A> func2(); B<A>::C_type func3(); B<Other>::C_type func4(); A is an incomplete type:
[2003: 9.2/2]:class is considered a fully defined object type (3.9) (or a full type) when closing}the class specifier. Within a class, a class is considered complete within functional bodies, default arguments, and ctor initializers (including such things in nested classes). Otherwise, it is considered incomplete within its class specification.
B<A> need to instantiate
func2 and func4 ok
Secondly, the return type of the function may be incomplete. This means that the return types func2 and func4 are exact like them.
[2003: 8.3.5/6]:[..] The parameter type or return type for the function definition should not be an incomplete class type (possibly cv-qualified) if the function definition is not embedded in the member specification for this class (including definitions in nested classes defined in the class).
func3 not ok
However, in a more complex func3 example, to use type B<A>::C_type , B<A> must be complete. *
And therefore it must also be created:
[2003: 14.7.1/1]:If the specialization of the class template was not explicit (14.7.2) or explicitly specialized (14.7.3), the template specialization is implicitly created if the specialization is referenced in a context that requires a fully defined object type or when the completeness of the class type affects the semantics of the program. [..]
But, since B<A> contains a member of type A , but A not a full type, and [8.3.5/6] requires it to be, the creation is invalid, B<A> remains incomplete ... and the program is poorly formed.
* I have not yet found a quote to support this, although this seems obvious.
I think the corresponding paragraph comes from classes 2:
A class is considered a fully defined type of object (3.9) (or a full type) when closing} the class specifier. Within a class, a class is considered complete within functional bodies, default arguments, exception specifications, and copied or equal initializers for non-static data members (including such things in nested classes). Otherwise, it is considered incomplete within its own class member specification.
B<A> func2() //A is incomplete here, but B<A> isn't instantiated { return B<A>(); //A is complete here } B<A>::C_type func3() //A is incomplete, B<A> needs to be instantiated for C_type { return B<A>::C_type(); //OK, A is complete } This is a circular link:
For the compiler to understand what structure A , it must be able to understand that B<A>::C_type (since it contains an element that returns an object of this type). So, in order to understand what B<A>::C_type , the compiler must understand what B<A> . But in order to understand what B<A> , the compiler must know what A .
In essence, you gave the compiler a paradox: to understand that A , you first need to know what A .