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() {} 
+4
source share
5 answers

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> .

+3
source

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.

+3
source

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 } 
+1
source

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 .

0
source

You can save the my_t element in template <typename T> struct B as a pointer and process its construction, destruction and copying into struct B , for example:

 template <typename T> struct B { typedef C<T> C_type; T* my_t; }; 
-1
source

All Articles