在尝试了解CRTP几天后,现在我的理解似乎比以前更少了:)
请考虑以下代码:
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 }
问题是:
为什么我可以从IMPL::
(第8行)调用函数但无法访问类型文件(第7行)?在相关问题中,据说IMPL
此时是不完整的类型。但为什么第8行是正确的呢?
类型声明/定义的顺序是什么?我认为:
一个。 Interface
模板 - 好的。在实例化之前不会带来任何问题
湾第11行 - 在class Implementation
- Implementation
类型声明但未定义之后。
℃。第11行 - 在Interface<Implementation>
之后 - 模板实例化。此时Implementation
由于步骤(b)已知(但未定义!)。编译器&#34;注入&#34;将IMPL
替换为Implementation
的代码。在我看来,第7行和第8行都不合法,因为此时编译器并不知道Implementation
有这些成员。它是如何知道的?
或者实例化可能真的排在第21行?但在那种情况下为什么第07行不起作用?
我想的更多,对我所拥有的C ++类型基础知识的理解较少。任何澄清都表示赞赏。
答案 0 :(得分:10)
实例化类模板时,非虚拟成员函数以外的成员将与其一起实例化。但是,非虚拟成员函数仅在使用odr时进行实例化(基本上,被调用或使用其地址)。
当编译器遇到class Implementation : public Interface<Implementation>
时,它需要实例化Interface<Implementation>
。此时,Implementation
仍然是一个不完整的类型,其TYPE
成员尚未被发现。另一方面,Interface<Implementation>::foo
仅在main
中调用时才会被实例化。此时,Implementation
是一个完整的类型。