Related questions: one, two
After trying to understand CRTP for several days it seems that now I understand even less than before:)
Consider the following code:
01 #include <iostream>
02
03 template <class IMPL>
04 class Interace
05 {
06 public:
07 typedef typename IMPL::TYPE TYPE; // ERROR: "...invalid use of incomplete type..."
08 void foo() { IMPL::impl(); } // then why does this work?
09 };
10
11 class Implementation : public Interface<Implementation>
12 {
13 public:
14 typedef int TYPE;
15 static void impl() { std::cout << "impl() " << std::endl; }
16 };
17
18
19 int main()
20 {
21 Implementation obj;
22 obj.foo();
23 }
The questions are:
Why I can call function from IMPL::
(line 8) but cannot access type fileds (line 7)? In related question it is said that IMPL
is an incomplete type at this point. But why then line 8 is correct?
What it the order of type declaration/definition? As I see it:
a. Interface
template -- OK. Doesn't bring any problems until instantiating
b. line 11 -- after class Implementation
-- Implementation
type declared but not defined.
c. line 11 -- after Interface<Implementation>
-- template instantiation. At this point Implementation
is already known (but not defined!) due to step (b). Compiler "injects" code with IMPL
replaced with Implementation
. Here, to my point of view, neither line 7, neither line 8 are not legal because at this point, compiler doesn't know that Implementation
has these members. How does it knows than?
Or maybe Instantiation really goes at line 21? But in that case why line 07 doesn't work?
More I think about it, less understanding of C++ type fundamentals I have. Any clarification is appreciated.
When a class template is instantiated, its members other than non-virtual member functions are instantiated together with it. Non-virtual member functions, however, are only instantiated when odr-used (basically, called or have their address taken).
When the compiler encounters class Implementation : public Interface<Implementation>
, it needs to instantiate Interface<Implementation>
. At this point, Implementation
is still an incomplete type, its TYPE
member has not yet been seen. On the other hand, Interface<Implementation>::foo
is only instantiated later, when it's called in main
. At that point, Implementation
is a complete type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With