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

问题描述 投票:0回答:1

相关问题:一个两个

尝试了解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();
}

问题是:

  1. 为什么我可以从

    IMPL::
    (第 8 行)调用函数,但无法访问类型字段?在相关问题中,据说
    IMPL
    此时是一个不完整的类型。但为什么第 8 行是正确的?

  2. 类型声明/定义的顺序是什么?据我看来:

a.

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

b.第 11 行 -- 在

class Implementation
之后 --
Implementation
类型声明但未定义。

c.第 11 行 - 在

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

或者也许实例化真的在第 21 行进行?但既然如此,为什么 07 号线不起作用呢?

我思考得越多,对 C++ 类型基础知识的了解就越少。任何澄清表示赞赏。

c++ c++11 crtp incomplete-type
1个回答
18
投票

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

当编译器遇到

class Implementation : public Interface<Implementation>
时,需要实例化
Interface<Implementation>
。此时,
Implementation
仍然是一个不完整的类型,它的
TYPE
成员尚未出现。另一方面,
Interface<Implementation>::foo
仅在稍后在
main
中调用时才被实例化。此时,
Implementation
就是一个完整的类型。

© www.soinside.com 2019 - 2024. All rights reserved.