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

Posted

技术标签:

【中文标题】CRTP——访问不完整的类型成员【英文标题】:CRTP -- accessing incomplete type members 【发布时间】:2016-05-27 11:42:40 【问题描述】:

相关问题:one、two

在尝试了解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 模板——好的。在实例化之前不会带来任何问题

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

    c。第 11 行——Interface&lt;Implementation&gt; 之后——模板实例化。由于步骤 (b),此时 Implementation 是已知的(但未定义!)。编译器“注入”代码,将 IMPL 替换为 Implementation。在我看来,第 7 行和第 8 行都不合法,因为此时编译器不知道 Implementation 有这些成员。它怎么知道呢?

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

我想得越多,我对 C++ 类型基础的理解就越少。任何澄清表示赞赏。

【问题讨论】:

【参考方案1】:

当一个类模板被实例化时,它的非虚成员函数以外的成员也随之被实例化。然而,非虚拟成员函数只有在使用 odr 时才会被实例化(基本上是调用或获取它们的地址)。

编译器遇到class Implementation : public Interface&lt;Implementation&gt;,需要实例化Interface&lt;Implementation&gt;。此时,Implementation 仍然是一个不完整的类型,它的TYPE 成员还没有被看到。另一方面,Interface&lt;Implementation&gt;::foo 仅在稍后在main 中调用时才实例化。此时,Implementation 是一个完整的类型。

【讨论】:

将附加参数传递给Interface,如Implementation : public Interface&lt;Implementation, int&gt;。从该参数中有Interface typedef TYPE,然后Implementation 不需要。

以上是关于CRTP——访问不完整的类型成员的主要内容,如果未能解决你的问题,请参考以下文章

指向不完整类型成员函数的指针

通过指向base,static_cast,crtp,删除模板的指针派生的成员

c语言报错不允许使用不完整类型,让用户自定义数组大小。

c struct queue error:“数组类型具有不完整的元素类型”

C++ 隐藏继承层次结构中的成员函数,紧盯 CRTP

c++ CRTP 中判断 Derived 中有没有某个成员函数