尝试了解CRTP几天后,现在看来我的理解比以前还要少:)
考虑以下代码:
#include <iostream>
template <class IMPL>
class Interace
{
public:
typedef typename IMPL::TYPE TYPE; // ERROR: "...invalid use of incomplete type..."
void foo() { IMPL::impl(); } // then why does this work?
};
class Implementation : public Interface<Implementation>
{
public:
typedef int TYPE;
static void impl() { std::cout << "impl() " << std::endl; }
};
int main()
{
Implementation obj;
obj.foo();
}
问题是:
为什么我可以从
IMPL::
(第 8 行)调用函数,但无法访问类型字段?在相关问题中,据说 IMPL
此时是一个不完整的类型。但为什么第 8 行是正确的?
类型声明/定义的顺序是什么?据我看来:
a.
Interface
模板——好的。在实例化之前不会带来任何问题
b.第 11 行 -- 在
class Implementation
之后 -- Implementation
类型声明但未定义。
c.第 11 行 - 在
Interface<Implementation>
之后 - 模板实例化。此时,由于步骤 (b),Implementation
已经已知(但未定义!)。编译器“注入”代码,并将 IMPL
替换为 Implementation
。在我看来,第 7 行和第 8 行都不合法,因为此时编译器不知道 Implementation
有这些成员。它怎么知道比?
或者也许实例化真的在第 21 行进行?但既然如此,为什么 07 号线不起作用呢?
我思考得越多,对 C++ 类型基础知识的了解就越少。任何澄清表示赞赏。
当类模板被实例化时,其非虚成员函数以外的成员也随之被实例化。然而,非虚拟成员函数仅在使用 odr 时才会实例化(基本上是调用或获取其地址)。
当编译器遇到
class Implementation : public Interface<Implementation>
时,需要实例化Interface<Implementation>
。此时,Implementation
仍然是一个不完整的类型,它的TYPE
成员尚未出现。另一方面,Interface<Implementation>::foo
仅在稍后在 main
中调用时才被实例化。此时,Implementation
就是一个完整的类型。