从不完整的类继承的类模板
Class template inheriting from incomplete class
由于继承了不完整的类型,因此此代码无法编译(https://godbolt.org/z/G35wj9):
template<typename>
class Incomplete;
class T : public Incomplete<T> {};
template<typename>
class Incomplete {};
int main()
{
[[maybe_unused]] T x;
}
我相信这个规则也适用于类模板。但是,此代码编译良好(https://godbolt.org/z/cU6GNt):
template<typename>
class Incomplete;
template<int d>
class T : public Incomplete<T<d>> {};
template<typename>
class Incomplete {};
int main()
{
[[maybe_unused]] T<1> x;
}
当涉及到类模板时,基类是否只需要在实例化时完成?
当涉及类模板时,基类是否只需要在实例化时完成?
如果它是一个依赖的基,那么是。因此,编译器在定义模板时不知道Incomplete<T<d>>
是什么。毕竟,对于d
的某些值,我们可以对Incomplete<T<d>>
进行专门化,这与主模板声明完全不同。
template<>
class Incomplete<T<0>> {};
这不是循环依赖关系。简单地将专门化命名为T<0>
不会导致它被实例化。这只是一个类型名称。但这确实意味着编译器没有追索权,只能等到它可以检查基类是否有效。
另一方面,如果基类不是依赖类型,那么将其用作基类将是不正确的。
标准在[temp.inst]§1(取自C++17(:中涵盖了这一点
除非类模板专门化已显式实例化(17.7.2(或显式专门化(17.7.3(,否则当在需要完全定义的对象类型的上下文中引用该专门化时,或者当类类型的完整性影响程序的语义时,类模板专化将隐式实例化。[注意:特别是,如果表达式的语义取决于类模板专用化的成员或基类列表,则类模板专用性是隐式生成的。例如,删除指向类类型的指针取决于该类是否声明了析构函数,而指向类类型指针之间的转换取决于继承关系在涉及的两个班之间。——尾注][示例:
template<class T> class B { /* ... */ };
template<class T> class D : public B<T> { /* ... */ };
void f(void*);
void f(B<int>*);
void g(D<int>* p, D<char>* pp, D<double>* ppp) {
f(p); // instantiation of D<int> required: call f(B<int>*)
B<char>* q = pp; // instantiation of D<char> required: convert D<char>* to B<char>*
delete ppp; // instantiation of D<double> required
}
--结束示例]如果在实例化时(17.6.4.1(已经声明了类模板,但没有定义,则实例化会产生不完整的类类型(6.9(
template<class T> class X;
X<char> ch; // error: incomplete type X<char>
--结束示例][注意:在模板声明中,本地类(12.4(或枚举以及本地类的成员永远不会被视为可以单独实例化的实体(这包括它们的默认参数、noexcept说明符和非静态数据成员初始值设定项,如果有的话(因此,查找依赖名称,检查语义约束,并将使用的任何模板实例化为实体实例化的一部分,在实体实例化中声明本地类或枚举。——尾注]
cppreference中也有介绍。
请记住,类模板不是类型,也不会为其生成代码。代码是在模板实例化时生成的。当类模板被实例化(隐式或显式(时,就会生成一个实际的类(类型((包括它的代码(。
唯一的区别是,在您的示例中,您在模板内部使用了Incomplete类。
在最初的例子中,它被一个类使用。此时编译器将创建类的类型,因此在定义Incomplete
之前。
在您的代码中,Incomplete
被用于另一个模板T
中(粗略地说:T
是一个使用Incomplete
生成各种类型的模具(。此时编译器什么也不做,它只存储一个"生成类型的规则"(我称之为模具(
编译器在使用T
时检查它的有效性,因此在第行-然后生成实际类型T<1> : public Incomplete
。T
(模具(是"有效的",如果Incomplete
定义为
[[maybe_unused]] T<1> x;
在这一点上,模板类Incomplete
定义得很好,编译器也很满意。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何在QT Creator上将QWidget声明为继承类的对象