Mat*_*ose 27 c++ static templates
在C++中,如果在header.hpp中定义此函数
void incAndShow()
{
static int myStaticVar = 0;
std::cout << ++myStaticVar << " " << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
并且在至少两个.cpp文件中包含header.hpp.然后你会有multiple definition of incAndShow().这是预期的.但是,如果您向该函数添加模板
template <class T>
void incAndShow()
{
static int myStaticVar = 0;
std::cout << ++myStaticVar << " " << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
那你就不会有任何multiple definition of错误.同样,两个不同的.cpp调用具有相同模板(例如incAndShow<int>())的函数将共享myStaticVar.这是正常的吗?我问这个问题,因为我确实依赖于这个"功能"(共享静态变量),我想确保不仅是我的实现正在这样做.
Joh*_*itb 31
你可以依靠这个.ODR(一个定义规则)3.2/5在标准中说,其中D代表非静态功能模板(由我提供的草书字体)
如果D是模板,并且是在多个翻译单元中定义的,那么上面列表中的最后四个要求将应用于模板定义(14.6.3)中使用的模板封闭范围中的名称,以及相关名称在实例化时(14.6.2).如果D的定义满足所有这些要求,那么程序应该表现得就像D的单个定义一样.如果D的定义不满足这些要求,则行为是不确定的.
在最后四个要求中,最重要的两个是粗略的
编辑
我认为单凭这一点不足以保证不同实例中的静态变量都是相同的.以上仅保证模板的多个定义有效.它没有说明由它产生的特化.
这就是连接起作用的地方.如果函数模板特化(这是一个函数)的名称有外部链接(3.5/4),那么引用这种特化的名称引用相同的函数.对于声明为static的模板,从中实例化的函数具有内部链接,因为
从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同.
-- 14/4具有命名空间作用域(3.3.6)的名称具有内部链接,如果它是显式声明为静态的对象,引用,函数或函数模板的名称
-- 3.5/3
如果函数模板没有用static声明,那么它有外部链接(顺便说一下,这也是我们必须遵循ODR的原因.否则,D根本不会多次定义!).这可以来自14/4(与...一起3.5/3)
非成员函数模板可以具有内部链接; 任何其他模板名称都应具有外部链接.
-- 14/4.
最后,我们得出结论,从具有外部链接的函数模板生成的函数模板特化通过3.5/4以下方式自身具有外部链接:
具有命名空间范围的名称具有外部链接,如果它是函数的名称,除非它具有内部链接
-- 3.5/4
当它具有内部链接时,3.5/3由明确的特化提供的函数和14/4生成的特化(模板实例化)解释.由于您的模板名称具有外部链接,因此您的所有特化都具有外部链接:如果您使用incAndShow<T>来自不同翻译单元的名称(),它们将引用相同的函数,这意味着您的静态对象在每种情况下都是相同的.
我理解你的问题.您要问的是,模板化函数的每个版本都有自己的myStaticVar实例是否正常.(例如:incAndShow<int>vs intAndShow<float>.答案是肯定的.
你的另一个问题是,如果两个文件包含包含模板函数的标题,它们是否仍会共享给定T的静态变量.我会说是的.