使用 `extern template` 防止模板的隐式实例化 class
Using `extern template` to prevent implicit instantiation of a template class
考虑以下代码片段:
template <typename>
struct X { };
extern template struct X<int>;
int main()
{
X<int>{};
}
编译并 links: live example on godbolt.org。由于 extern template
声明,我希望它不会 link。
我的理解是extern template
的意思是:"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".
examples/descriptions。我在 isocpp 和 cppreference 上看到的似乎验证了我的心智模型。例如
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.
为什么我的代码片段 link?这里到底发生了什么?
编辑 - 在最新的标准草案中找到:
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.
这是否意味着我发布的代码片段格式错误,NDR?
Why does my code snippet link? What is actually happening here?
嗯,没什么到link。因为必须考虑显式实例化的影响。来自 n3337:
[temp.explicit] (emphasis mine)
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. [ 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. — end
note ]
因此 class 模板特化 X<int>
的隐式实例化没有被抑制。它也是一个聚合,所以它的初始化是内联的,我们没有得到任何反对 link 的东西。但是,如果它有任何成员,那些 将 隐藏在段落 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.
所以如果你有类似这样的东西而不是聚合:
template <typename>
struct X {
X();
};
template <typename T>
X<T>::X() {}
extern template struct X<int>;
int main()
{
X<int>{};
}
如您所料,那会失败,因为它 ODR 使用其定义从未实例化的构造函数。声明 是 实例化的,因为封闭的特化是实例化的,如上所述。但是在显式实例化声明的抑制作用下,我们永远得不到任何定义。
Does this mean that the code snippet I posted is ill-formed, NDR?
是的,完全按照您引用的 [temp.explicit]/13 中的句子。 "An entity" 就是这个意思。显式实例化声明是否没有规范效果并不重要。
考虑以下代码片段:
template <typename>
struct X { };
extern template struct X<int>;
int main()
{
X<int>{};
}
编译并 links: live example on godbolt.org。由于 extern template
声明,我希望它不会 link。
我的理解是extern template
的意思是:"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".
examples/descriptions。我在 isocpp 和 cppreference 上看到的似乎验证了我的心智模型。例如
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.
为什么我的代码片段 link?这里到底发生了什么?
编辑 - 在最新的标准草案中找到:
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.
这是否意味着我发布的代码片段格式错误,NDR?
Why does my code snippet link? What is actually happening here?
嗯,没什么到link。因为必须考虑显式实例化的影响。来自 n3337:
[temp.explicit] (emphasis mine)
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. [ 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. — end note ]
因此 class 模板特化 X<int>
的隐式实例化没有被抑制。它也是一个聚合,所以它的初始化是内联的,我们没有得到任何反对 link 的东西。但是,如果它有任何成员,那些 将 隐藏在段落 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.
所以如果你有类似这样的东西而不是聚合:
template <typename>
struct X {
X();
};
template <typename T>
X<T>::X() {}
extern template struct X<int>;
int main()
{
X<int>{};
}
如您所料,那会失败,因为它 ODR 使用其定义从未实例化的构造函数。声明 是 实例化的,因为封闭的特化是实例化的,如上所述。但是在显式实例化声明的抑制作用下,我们永远得不到任何定义。
Does this mean that the code snippet I posted is ill-formed, NDR?
是的,完全按照您引用的 [temp.explicit]/13 中的句子。 "An entity" 就是这个意思。显式实例化声明是否没有规范效果并不重要。