These are "circular dependencies" or "incomplete" alter ego.
The “meta-programming” template is “programming types”, but this requires a certain level of semantics for the correct creation of types.
Consider this analogy :
class A; //forwarded class B { A* pa;
This can be solved by putting A in front of B, but if A is
class A { B m; };
There is no other solution than pointers, since the recursion will be infinite. (A must contain itself, not reference another copy)
Now with the same analogy , let the program "types":
template<class D> class A { typedef typename D::inner_type my_type;
This declaration alone is not bad, until we begin to define D as ...
class D: //here we only know D exist public A<D> //but A size depende on D definition... { .... typedef long double; inner_type .... }; // ....we know only starting from here
So basically, we don’t yet know how wide A is at the time when you need to use it to create D.
One way to break this “roundness” is to use some “feature classes” outside the CRT loop:
struct traits { typedef long double inner_type; .... }; template<class D, class Traits> class A {
We can finally announce
typedef D<traits> D_Inst;
In other words, the coherence between
A::my_type and
D::inner_type provided by
traits::inner_type , the definition of which is independent.