使用`extern template`防止模板类的隐式实例化

罗密欧

考虑以下代码片段:

template <typename>
struct X { };

extern template struct X<int>;

int main()
{
    X<int>{};
}

它编译并链接:Godbolt.org上的实时示例由于extern template声明,我希望它不会链接

我的理解是extern template“请不要在此TU中实例化此特定模板的特殊化,它将由其他TU提供,您可以对其进行链接”

示例/说明。我在isocppcppreference上看到似乎可以验证我的心理模型。例如

https://en.cppreference.com/w/cpp/language/class_template

显式实例化声明(外部模板)跳过隐式实例化步骤:否则会导致隐式实例化的代码将改用其他地方提供的显式实例化定义(如果不存在此类实例,则会导致链接错误)通过在使用该源文件的一个源文件中显式声明一个模板实例化,并在其余文件中显式定义它,可以用于减少编译时间。

为什么我的代码段链接?这里到底发生了什么?


编辑-在最新的标准草案中找到了这一点:

[温度显式]

如果一个实体是同一翻译单元中的显式实例化声明和显式实例化定义的主体,则该定义应遵循该声明。一个实体是显式实例化声明的主题,并且以某种方式使用,否则该实体将在翻译单元中引起隐式实例化,则该实体应是程序中某个位置的显式实例化定义的主题;否则,程序格式错误,无需诊断。

这是否意味着我发布的代码段格式不正确,即NDR

讲故事的人-Unslander Monica

为什么我的代码段链接?这里到底发生了什么?

好吧,没有什么链接的。因为必须考虑显式实例化的影响。从n3337:

[temp.explicit](强调我的)

10 除内联函数和类模板专门化外,显式实例化声明还具有抑制其所引用实体的隐式实例化的作用。[注意:意图是作为显式实例化声明的主题的内联函数在odr-use([basic.def.odr])时仍将隐式实例化,以便可以将主体视为内联,但不能内联函数的脱机副本将在翻译单元中生成。—尾注]

因此X<int>,不会抑制类模板专门化的隐式实例化它也是一个聚合,因此它的初始化是内联的,因此我们无法进行链接。但是,如果有任何成员,则根据第8其删除

命名类模板专门化的显式实例化也是其每个成员(不包括从基类继承的成员)的相同种类(声明或定义)的显式实例,该成员先前未明确地包含在包含显式实例化,除非如下所述。

因此,如果您没有类似的汇总,而是:

template <typename>
struct X {
    X();
};

template <typename T>
X<T>::X() {}     

extern template struct X<int>;

int main()
{
    X<int>{};
}

正如您所料,这将失败,因为ODR使用了永远不会实例化其定义的构造函数。如上所述,声明实例化,因为封闭的专业化被实例化。但是,在显式实例化声明的抑制作用下,我们从未得到任何定义。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用extern并防止重复定义

在不使用“ extern”的情况下分隔模板类的定义/实例化

防止隐式模板实例化

可以在类中使用extern变量吗?

使用extern从Haxe访问C ++类

使用模板参数实例化模板类

使用extern引用非静态内联函数的实例化

使用元组显式实例化模板

类模板的静态成员是否隐式实例化?

模板类的虚函数是否隐式实例化?

使用模板化构造函数实例化非模板类

在类方法中使用extern数组->未定义引用

使用extern“ C”在C文件中调用C ++类函数

在类定义中使用extern decl-specifier编程

extern模板“不一致的显式实例化”

使用指向extern变量的指针进行静态初始化

类模板的条件无效成员函数(隐式实例化;显式实例化失败)

使用参数实例化模板类的类成员的正确方法

使用别名的显式模板实例化?

使用clang的显式C ++模板实例化

使用私有构造函数来防止类的实例化?

如何使用模板template参数显式实例化函数

模板:使用类类型的成员实例化对象

使用boost预处理实例化模板函数和类

clang:使用O3导出隐式实例化函数的符号

Axon使用无参数构造函数隐式实例化另一个聚合

Scala隐式类(在隐式类内部使用隐式)-不是Int错误的成员

如何在库中使用C ++ 11中的“ extern”将定义与类模板的声明分开来(dll,所以..)

如果将extern模板类仅使用一个翻译单元,为什么没有链接错误?