CRTP - 访问不完整类型的成员

时间:2016-02-16 09:22:50

标签: c++ c++11 crtp incomplete-type

相关问题:onetwo

在尝试了解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 }

问题是:

  1. 为什么我可以从IMPL::(第8行)调用函数但无法访问类型文件(第7行)?在相关问题中,据说IMPL此时是不完整的类型。但为什么第8行是正确的呢?

  2. 类型声明/定义的顺序是什么?我认为:

    一个。 Interface模板 - 好的。在实例化之前不会带来任何问题

    湾第11行 - 在class Implementation - Implementation类型声明但未定义之后。

    ℃。第11行 - 在Interface<Implementation>之后 - 模板实例化。此时Implementation由于步骤(b)已知(但未定义!)。编译器&#34;注入&#34;将IMPL替换为Implementation的代码。在我看来,第7行和第8行都不合法,因为此时编译器并不知道Implementation有这些成员。它是如何知道的?

  3. 或者实例化可能真的排在第21行?但在那种情况下为什么第07行不起作用?

    我想的更多,对我所拥有的C ++类型基础知识的理解较少。任何澄清都表示赞赏。

1 个答案:

答案 0 :(得分:10)

实例化类模板时,非虚拟成员函数以外的成员将与其一起实例化。但是,非虚拟成员函数仅在使用odr时进行实例化(基本上,被调用或使用其地址)。

当编译器遇到class Implementation : public Interface<Implementation>时,它需要实例化Interface<Implementation>。此时,Implementation仍然是一个不完整的类型,其TYPE成员尚未被发现。另一方面,Interface<Implementation>::foo仅在main中调用时才会被实例化。此时,Implementation是一个完整的类型。