哪里需要完整的类型(不需要)
Where are complete types (not) required?
我最近很惊讶地发现,这段代码编译(至少在gcc和MSVC++上):
template<typename T>
class A {
public:
T getT() { return T(); }
};
class B : public A<B> { };
如果没有:
class A;
class B : public A { };
class A {
public:
B getB() { return B(); }
};
在我看来,一个模板类可以将一个不完整的类型作为模板参数,并通过调用其构造函数返回一个函数,但仍然可以编译,这似乎很奇怪。那么,哪里需要完整的类型(或者如果列表更短,哪里不需要)?
以下是不需要完整类型的场景:
- 将成员声明为指向不完整类型的指针或引用
- 声明接受/返回不完整类型的函数
- 定义接受/返回指向不完整类型的指针/引用的函数
- 作为模板类型参数
基本上,在编译器不需要知道type
的内存布局的任何地方,使用Incomplete类型都可以。
至于允许模板类型参数为不完整类型,标准在14.3.1模板类型参数
这就是CRTP在两阶段模板解析中的工作方式。模板成员函数在实例化之前不会被解析。
编辑:也许,措辞不是很精确。当编译器看到class B : public A< B > {...};
,它经过A< B >
,注意到有一个函数B get() {...}
,但不评估其定义,直到函数的实际实例化,此时B
必须是一个完整的类型。
编辑:我相信,标准第14.6节中涵盖了确切的规则(正如Als在回答中指出的那样)。根据两阶段的模板名称查找,处理了dependent
和non-dependent
的名称及其在编译过程中不同时间的解析。然而,不幸的是,在不同的编译器上,两阶段名称查找实现可能与Standard不同。相同的代码可能在GCC上编译,也可能不在MSVC++上编译,反之亦然。更重要的是,看似相同的代码可能会被相同的编译器拒绝。在MSVC++上,当基类使用指向派生类函数的指针作为其函数的默认参数时,我遇到了一个问题。它没有在MSVC++下编译,而是在GCC下编译(正确)。但是,即使在MSVC++上,也要使用派生类构造函数作为两个编译器编译的默认参数。转到图。
模板并不是真正的代码;这是一个模板,它描述了一旦您填充了缺失的部分(类型参数),如何构建代码。正因为如此,编译器在模板定义中比在实际代码定义中有更多的余地。当您实际使用模板并识别类型时,编译器需要生成实际代码,并应用所有常用规则。
如果编译器不需要知道对象成员的大小或偏移量,则不需要完整的定义。例如,定义指向类的指针或引用不需要这两者。当您尝试使用指针或引用时,您将需要一个完整的定义。
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 为什么转换函数声明不需要至少一个定义类型说明符
- 为什么不需要在 C++20 中的依赖类型之前指定"typename"?
- 为什么在以下情况下不需要为依赖类型使用typename
- 为什么 pair 在初始化中不需要类型
- 为什么在VS2015中模板相关的嵌套类型名称中不需要typename关键字?
- 为什么嵌套类型的基类不需要"typename"?
- 为什么一元运算符和不需要完整类型?
- 为什么嵌套类的成员函数不需要完整类型?
- 为什么 c++ lambda 捕获不需要类型声明?
- 不需要增量锁的 C++ 计数器类型
- 如果 std::shared_ptr 是从非 null 构造的,为什么它不需要知道完整的类型?
- 检测类型何时不需要调用其析构函数
- 模板类和处理不需要的类型声明的良好实践
- 哪里需要完整的类型(不需要)
- 使用函子的返回类型来声明模板方法的返回类型,不需要decltype
- c++调用约定是否受标准约束,因为在声明fn时不需要定义函数的返回类型
- 退货类型中不需要模板参数
- c++:包含对象的确切类型,不需要强制类型转换
- 在c++中,如何解析文本文件后面不需要的文本中的任何数据类型