繁体   English   中英

CRTP 和不完整类型

[英]CRTP and Incomplete Types

我想简要说明一下完整类型与 CRTP 的关系。 我认为这个问题有点相关。 但是,我的问题与 CRTP 有关,其中派生类成员函数显式调用基类成员函数,而基类成员函数又调用派生函数。 这似乎与在主例程中调用派生类型的基类函数不同。

我还阅读了这个问题,其中解释了使用派生类的基类的static constexpr成员在编译器看到派生类并完成之前不会初始化。 但是在这种情况下,派生类也被模板化了。

这是我的问题。 考虑

template<typename D> struct B{
  void foo() const { static_cast<const D*>(this)->baz(); }
};

struct D : B<D> {
  void bar() const { foo(); }
  void baz() const {}
};

据我了解,在类的右大括号之前,每个D仍然是不完整的类型。 我也知道成员函数模板在使用之前不会被实例化。 因此,如果我们暂时忽略D::bar ,则以下内容在 main 中有效是有道理的:

D d; d.foo(); 

我需要进一步澄清的是什么是使用? 例如,在定义D::bar时,有一个对B::foo的调用(因此该函数可能在那里被实例化),这将要求D是一个完整的类型。 但是在定义D::bar时, D并不完整。 或者是吗?

我想也许可能发生的是,在定义D::bar并调用B::foo的地方,它会强制编译器为B::foo进行声明(不需要定义)。 也许直到D::bar在其他某个时间点实际调用时才发生定义。 但是我在C++ Insights上运行了这个并且变得更加困惑,因为BB<D>的显式特化甚至在D被声明之前就发生了。 澄清将不胜感激!

使用B<D>作为D的基类要求B<D>是一个完整的类。 因此,它将导致B<D>的隐式实例化。

类特化的实例化点就在需要它的命名空间范围声明之前,即在D的定义之前。 (通过[temp.point]/4

B<D>的隐式实例化不会导致foo的成员函数定义的隐式实例化。 因此,这里不需要完成D


定义

void bar() const { foo(); }

有一个 ODR 使用foo 因此它将导致B<D>::foo的隐式实例化。

成员函数特化的实例化点位于命名空间范围声明之后和翻译单元的末尾。 (通过[temp.point]/1[temp.point]/7.1

这两个都在D的定义之后,因此D将在这些点上完成。 因此static_cast<const D*>(this)->baz(); 不是问题。


请注意, D不是模板。 模板实例化规则不适用于它。 使用或引用bar并不重要。 是否使用D d; d.foo(); D d; d.foo(); 或任何遵循D定义的东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM