首页 > 解决方案 > 从模板化基类派生是否在派生类声明时实例化模板?

问题描述

给定以下示例代码:

// 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包含模板时都被实例化?

标签: c++

解决方案


显式实例化声明 ( 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

但是,这显然会限制包含标头的代码可以完成的工作。


推荐阅读