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<Implementation>
之后——模板实例化。由于步骤 (b),此时 Implementation
是已知的(但未定义!)。编译器“注入”代码,将 IMPL
替换为 Implementation
。在我看来,第 7 行和第 8 行都不合法,因为此时编译器不知道 Implementation
有这些成员。它怎么知道呢?
或者实例化真的在第 21 行?但在那种情况下,为什么第 07 行不起作用?
我想得越多,我对 C++ 类型基础的理解就越少。任何澄清表示赞赏。
【问题讨论】:
【参考方案1】:当一个类模板被实例化时,它的非虚成员函数以外的成员也随之被实例化。然而,非虚拟成员函数只有在使用 odr 时才会被实例化(基本上是调用或获取它们的地址)。
编译器遇到class Implementation : public Interface<Implementation>
,需要实例化Interface<Implementation>
。此时,Implementation
仍然是一个不完整的类型,它的TYPE
成员还没有被看到。另一方面,Interface<Implementation>::foo
仅在稍后在main
中调用时才实例化。此时,Implementation
是一个完整的类型。
【讨论】:
将附加参数传递给Interface
,如Implementation : public Interface<Implementation, int>
。从该参数中有Interface
typedef TYPE
,然后Implementation
不需要。以上是关于CRTP——访问不完整的类型成员的主要内容,如果未能解决你的问题,请参考以下文章
通过指向base,static_cast,crtp,删除模板的指针派生的成员