Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Curiously Recurring Template Pattern Implementation Specific?

So I've read through this: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

And understand how Curiously Recurring Template Pattern (CRTP) works. But it seems like it depends upon the compiler implementation, specifically that the compiler:

  1. Defines the space required for each Template Class
  2. Then compiles the child class's methods
  3. Then compiles the parent class's methods

While I can see how this order allows compilation I feel like it's an leveraging compiler construction rather than an order of compiler passes required by the standard. But I feel like an equally legitimate set of compiler passes would be to:

  1. Define the space required for the parent class
  2. Compile the parent classes methods
  3. Define the space required for the child class
  4. Compile the child classes methods

If the compiler used these passes CRTP would fail on step 2 when it attempts to evaluate a child type.

So I've just made up these compiler passes, but is there a standard requirement that places constraints on the compiler that it much adhere to the 3 passes of the 1st? Or does CRTP exist in a grey area of knowing how compilers are implemented currently?


As I see it to allow that the standard would need to require a 1st pass that establishes object sizes, followed by a 2nd pass that compiles methods. But this 2nd pass wold have to be willing to build a child objects methods before the parent objects, which seems backwards.

like image 276
Jonathan Mee Avatar asked Jun 26 '26 08:06

Jonathan Mee


2 Answers

CRTP was never implementation defined or conditionally supported, IIRC it was a pleasant surprise at the time of invention and has been accepted ever since.

From [class]

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

Where class-name is the name of the class being declared. Therefore the class-name is already visible before the base-clause, which is the list of bases, but the class is complete only after its full definition.

However, templates are allowed to use incomplete types as its type-arguments, from [temp]

A template type argument may be an incomplete type.

Note the template is complete even if its type arguments aren't.

template<typename>
struct S {};

struct U     // U is visible after this line
    : S<U>   // S<U> is a complete type
{
    S<U> s;  // well-formed
};           // U is complete after this line

The reason the instantiated template can be complete is because the template type arguments may themselves be incomplete within the template, thereby avoiding cyclic logic

template<typename T>
struct A
{
    T t;  // ill-formed, incomplete type T in instantiation of A<B> from below
};

struct B : A<B>  // implicit instantiation of the specialization A<B>
{
};

We conclude the pattern is valid. How the compiler manages to compile it is irrelevant, if it is standard conformant, it will compile that code.

like image 118
Passer By Avatar answered Jun 27 '26 21:06

Passer By


This is well-defined. As noted in comments, even the standard utilizes the functionality.

The way to think about it is that as soon as you write class Child the compiler considers that effectively a forward declaration of the type. So as long as the parent class template definition doesn't depend on the complete type of Child the parent it will compile successfully. [I believe that the size of the parent template class cannot depend on the definition of Child but I can't prove that to myself] Note that the parent template method bodies are free to rely on the complete type of child because they will be dependent types and thus their instantiation is delayed to the second phase of template compilation when the full definition of Child is available.

like image 40
Mark B Avatar answered Jun 27 '26 21:06

Mark B