Where are the full types (not) required?

I was recently surprised to learn that this code compiles (at least on gcc and MSVC ++):

template<typename T> class A { public: T getT() { return T(); } }; class B : public A<B> { }; 

If this is not the case:

 class A; class B : public A { }; class A { public: B getB() { return B(); } }; 

It seems strange to me that a template class can take an incomplete type as a template parameter and have a function that returns it, calling its constructor and still compiling. So where exactly are the full types required (or if the list is shorter where they are not needed)?

+2
c ++ incomplete-type
source share
3 answers

The following are scenarios in which full types are not required:

  • Declaring an element as a pointer or reference to an incomplete type.
  • Declaring functions that accept / return incomplete types.
  • Defining functions that accept / return pointers / references to an incomplete type.
  • As an argument to the template type.

Basically, you make good use of an incomplete type anywhere where the compiler does not need to know the type memory layout.

As for the template type argument, which is allowed as an incomplete type, the standard explicitly talks about this in 14.3.1. Pattern Type Arguments

+4
source share

Here's how CRTP works because of the two-step parsing of templates. The functions of the template members are not analyzed until they are created.

EDIT: Perhaps the wording is not very accurate. What I wanted to say when the compiler sees class B : public A< B > {...}; , it passes through A< B > , notices that there exists a function B get() {...} , but does not evaluate its definition, leaving it up to the actual actual instance of the function at which point B must be a full type.

EDIT: I believe that the exact rules are described in standard section 14.6 (as Als pointed out in his answer). It deals with dependent and non-dependent names and their resolution at different times during compilation in accordance with the search for two-phase name names. However, unfortunately, the implementation of a two-stage search may differ from the standard for different compilers. The same code may compile in GCC and may not display on MSVC ++ and vice versa. Moreover, the same code can be rejected by the same compiler. In MSVC ++, I had a problem when the base class used a pointer to a derived function of the class as the default argument for its function. It did not compile under MSVC ++ and compiled under GCC (correctly). However, using the constructor of the derived class as the default parameter compiled with both compilers, even on MSVC ++. Hover over your mouse.

+4
source share

A template is not really code; This is a template that describes how to create code as soon as you fill in the missing parts (type parameters). Because of this, the compiler allows more discretion in the definition of the template than the actual definition of the code. When you actually use a template with the specified types, the compiler must generate the actual code and apply all the usual rules.

A full definition is not required unless the compiler needs to know the size or offsets for the members of the object. The definition of a pointer or class reference, for example, does not need any of them. The moment you try to use a pointer or link, you will need a full definition.

+1
source share

All Articles