Vit*_*meo 6 c++ templates extern language-lawyer c++11
Consider the following code snippet:
template <typename>
struct X { };
extern template struct X<int>;
int main()
{
X<int>{};
}
Run Code Online (Sandbox Code Playgroud)
It compiles and links: live example on godbolt.org. I would expect it not to link due to the extern template
declaration.
My understanding is that extern template
means: "please don't instantiate this particular template specialization in this TU, it will be provided by some other TU and you can link against it".
The examples/descriptions. I've seen on isocpp and cppreference seem to validate my mental model. E.g.
From https://en.cppreference.com/w/cpp/language/class_template:
An explicit instantiation declaration (an extern template) skips implicit instantiation step: the code that would otherwise cause an implicit instantiation instead uses the explicit instantiation definition provided elsewhere (resulting in link errors if no such instantiation exists). This can be used to reduce compilation times by explicitly declaring a template instantiation in all but one of the source files using it, and explicitly defining it in the remaining file.
Why does my code snippet link? What is actually happening here?
EDIT - found this in the latest Standard draft:
If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.
Does this mean that the code snippet I posted is ill-formed, NDR?
为什么我的代码段链接?这里到底发生了什么?
好吧,没有什么可链接的。因为必须考虑显式实例化的影响。从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>{};
}
Run Code Online (Sandbox Code Playgroud)
正如您所料,这将失败,因为ODR使用了永远不会实例化其定义的构造函数。如上所述,声明被实例化,因为封闭的专业化被实例化。但是,在显式实例化声明的抑制作用下,我们从未得到任何定义。
这是否意味着我发布的代码段格式不正确,即NDR?
是的,根据您引用的[temp.explicit] / 13中的确切句子。“实体”就是这样。显式实例化声明是否否则没有规范作用并不重要。