简体   繁体   English

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

[英]Using `extern template` to prevent implicit instantiation of a template class

Consider the following code snippet: 请考虑以下代码段:

template <typename>
struct X { };

extern template struct X<int>;

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

It compiles and links: live example on godbolt.org . 它编译和链接: godbolt.org上的实例 I would expect it not to link due to the extern template declaration. 由于extern template声明,我希望它不会链接。

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" . 我的理解是extern template意味着: “请不要在这个TU中实例化这个特定的模板专业化,它将由其他一些TU提供,你可以链接它”

The examples/descriptions. 示例/描述。 I've seen on isocpp and cppreference seem to validate my mental model. 我在isocpp看过cppreference似乎验证了我的心理模型。 Eg 例如

From https://en.cppreference.com/w/cpp/language/class_template : 来自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) . 显式实例化声明(extern模板)跳过隐式实例化步骤: 否则将导致隐式实例化的代码使用其他地方提供的显式实例化定义(如果不存在此类实例化,则会导致链接错误) 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: 编辑 - 在最新的标准草案中找到:

[temp.explicit] [temp.explicit]

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 ? 这是否意味着我发布的代码片段格式不正确,NDR

Why does my code snippet link? 为什么我的代码段链接? What is actually happening here? 这里到底发生了什么?

Well, there's nothing to link. 好吧,没有什么可以联系的。 For one has to consider the effects of the explicit instantiation. 因为必须考虑显式实例化的效果。 From n3337: 来自n3337:

[temp.explicit] (emphasis mine) [temp.explicit] (强调我的)

10 Except for inline functions and class template specializations , explicit instantiation declarations have the effect of suppressing the implicit instantiation of the entity to which they refer. 10 除了内联函数和类模板特化之外,显式实例化声明具有抑制它们引用的实体的隐式实例化的效果。 [ Note: The intent is that an inline function that is the subject of an explicit instantiation declaration will still be implicitly instantiated when odr-used ([basic.def.odr]) so that the body can be considered for inlining, but that no out-of-line copy of the inline function would be generated in the translation unit. [注意:意图是当使用odr([basic.def.odr])时,仍然会隐式实例化作为显式实例化声明主题的内联函数,以便可以考虑使用内联体,但是将在翻译单元中生成内联函数的外联副本。 — end note ] - 结束说明]

So the implicit instantiation of the class template specialization X<int> , is not suppressed. 因此,不抑制类模板特化X<int>的隐式实例化。 It's also an aggregate, so its initialization occurs inline, and we get nothing to link against. 它也是一个聚合,因此它的初始化是内联的,我们没有任何东西可以链接。 However, if it had any members, those would be suppressed under paragraph 8 : 但是,如果它有任何成员,那么根据第8段予以取消:

An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below. 命名类模板特化的显式实例化也是其每个成员(不包括从基类继承的成员)的相同类型(声明或定义)的显式实例化,该实例之前未明确专门化在包含该类的转换单元中。显式实例化,除非如下所述。

So if you had instead of an aggregate something akin to this: 所以,如果你有一个类似于此的汇总而不是:

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

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

extern template struct X<int>;

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

That would fail as you expect, since it ODR uses a constructor whose definition is never instantiated. 那会像你期望的那样失败,因为ODR使用的构造函数的定义从未实例化过。 The declaration is instantiated, because the enclosing specialization is instantiated, as mentioned above. 声明实例化的,因为封闭的特化是实例化的,如上所述。 But we never get any definition, under the suppressing effect of the explicit instantiation declaration. 但是在明确的实例化声明的抑制效果下,我们永远不会得到任何定义。

Does this mean that the code snippet I posted is ill-formed, NDR? 这是否意味着我发布的代码片段格式不正确,NDR?

Yes, by the exact sentence from [temp.explicit]/13 that you quoted. 是的,通过您引用的[temp.explicit] / 13中的确切句子。 "An entity" means just that. “一个实体”就是这个意思。 It does not matter if an explicit instantiation declaration otherwise have no normative effect. 如果显式实例化声明否则没有规范效果,则无关紧要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM