c++ - 从模板化基类派生是否在派生类声明时实例化模板?
问题描述
给定以下示例代码:
// Foo.hpp
template <typename T>
class Foo
{
};
extern template class Foo<int>;
class Bar : public Foo<int>
{
};
// Foo.cpp
template class Foo<int>;
模板会在's 声明Foo<int>
点被实例化吗?Bar
即从模板化的基类派生是否会导致该模板的隐式实例化?我的假设是,是的,它将被隐式实例化,但我不确定标准中的相关部分。如果模板在那一点被实例化,那么我假设使用extern template class Foo<int>;
变得完全多余?如果是这种情况,有什么办法可以防止每次Foo.hpp
包含模板时都被实例化?
解决方案
显式实例化声明 ( extern template
) 的目的是抑制隐式实例化并强制编译器生成外部引用。但是,在类的情况下,显式实例化声明不会抑制隐式实例化 ([temp.explicit]/10)。这是因为,虽然可以编译对未定义函数的调用(链接器将在看到定义时解析调用),但没有类似的机制来编译实例化不完整类或访问其成员的代码。
在您的情况下,Foo<int>
将在Bar
定义时实例化,因为 [temp.inst]/1 说:
除非类模板特化已显式实例化 (17.7.2) 或显式特化 (17.7.3),否则当在需要完全定义的对象类型的上下文中引用该类模板特化或完整性时,类模板特化将被隐式实例化。类类型的影响程序的语义。
类类型必须是完整的才能从它派生,因此这里指定了隐式实例化(并且,如前所述,显式实例化声明不会抑制这种隐式实例化)。
但是,说显式实例化必然没有效果是不正确的。它可能会在隐式实例化时抑制Foo<int>
's vtable 和/或 typeinfo 的生成。Foo<int>
可以在链接时发出和解析对此类实体的外部引用。
有什么方法可以防止每次包含 Foo.hpp 时都实例化模板?
这样做的唯一方法是 forward-declare Bar
:
class Bar; // not defined yet
但是,这显然会限制包含标头的代码可以完成的工作。
推荐阅读
- python - 小部件移动上的运行方法
- laravel - 由于 $filterarray 和 $set 使用相同的字段,MongoDB updateOne 无法正常工作
- wordpress - 将旧 WordPress 网站的内容导入新的 WordPress 网站
- amazon-web-services - AWS 子网没有 IP 地址(使用 CDK)
- javascript - Jest ReferenceError:您正在尝试在 Jest 环境被拆除后“导入”文件
- spring - SpringBoot开发工具热部署报错无法实例化DataSource
- java - 如何在android中禁用reCaptcha?
- linux - 在 Linux T2 实例 Localhost 上运行 Ansible Playbook 的问题
- c++ - 为什么多个函数调用在 Opengl 中不起作用?
- modelica - 运行脚本时是否可以更改模型的参数化?