这是C 11中extern模板的正确用法吗? (可以是extern模板类和相应的模板类在同一个翻译单元中可见吗?)
// example.hpp:
#pragma once
template< typename T >
class C {
void f(T);
};
// question is about the next two lines
extern template class C< float >;
extern template class C< double >;
// example_def.hpp:
#include "example.hpp"
template< typename T >
void C< T >::f(T) {
//... smth. practicable
}
// example.cpp:
#include "example_def.hpp"
template class C< float >;
template class C< double >;
// other.hpp:
#pragma once
void g();
// other.cpp:
#include "other.hpp"
#include "example.hpp"
// maybe those two lines should be here instead?
void g() {
C< float >();
C< double >();
}
// main.cpp:
#include "example.hpp"
#include "other.hpp"
// ...and here?
int main() {
C< float >();
C< double >();
g();
return 0;
}
解决方法:
是的,如果定义(没有extern)遵循声明,则extern模板类规范(标准称为显式实例化声明)和模板类规范(标准称为显式实例化定义)可以在同一个转换单元中(与extern):
(§14.7.2/11) 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 (14.7.1) 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. [ Note: This rule does apply to inline functions even though an explicit instantiation declaration of such an entity has no other normative effect. This is needed to ensure that if the address of an inline function is taken in a translation unit in which the implementation chose to suppress the out-of-line body, another translation unit will supply the body. — end note ] An explicit instantiation declaration shall not name a specialization of a template with internal linkage.
(强调我的).术语显式实例化声明和显式实例化定义在此定义:
(§14.7.2/2) The syntax for explicit instantiation is:
explicit-instantiation:
extern
opttemplate
declarationThere are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration. An explicit instantiation declaration begins with the extern keyword.
这些显式实例化的效果如下:
>显式实例化声明(使用extern)可防止所有隐式实例化生效(内联函数和类模板特化除外,§14.7.2/ 10).
>显式实例化定义(没有extern)导致实例化无论发生什么,即它都会覆盖显式实例化声明(这也遵循§14.7.2/ 10).
普通的留言
您的显式实例化声明位于定义模板的头文件中这一事实意味着包含头文件以便使用模板的任何人都必须添加显式实例化定义,或者,需要链接到包含此类显式实例化定义的另一个.cpp文件的代码.
这可能令人困惑,当您期望许多不同的用户为许多不同类型实例化模板时,这可能不是一个好主意.但是,如果不同类型的实例化数量很少并且您可以预测它们,那么这是明智的.当然,您必须确保有一个(或几个).cpp文件包含所需的所有实例化的显式实例化定义,并且其对应的目标文件在构建时与项目链接.