Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
模板函数中的静态变量 在C++中,如果在Health.Hpp中定义此函数 void incAndShow() { static int myStaticVar = 0; std::cout << ++myStaticVar << " " << std::endl; }_C++_Templates_Static - Fatal编程技术网

模板函数中的静态变量 在C++中,如果在Health.Hpp中定义此函数 void incAndShow() { static int myStaticVar = 0; std::cout << ++myStaticVar << " " << std::endl; }

模板函数中的静态变量 在C++中,如果在Health.Hpp中定义此函数 void incAndShow() { static int myStaticVar = 0; std::cout << ++myStaticVar << " " << std::endl; },c++,templates,static,C++,Templates,Static,这样就不会有任何错误的多个定义。同样,使用相同模板调用函数的两个不同的.cpp(例如incAndShow())将共享myStaticVar。这正常吗?我之所以问这个问题,是因为我确实依赖于这个“特性”(共享静态变量),我想确定的是,不仅仅是我的实现在做这件事。这样我才能理解您的问题。您会问,模板函数的每个版本都有自己的myStaticVar实例是否正常。(例如:incAndShowvs.intAndShow答案是肯定的 您的另一个问题是,如果两个文件包含包含模板函数的头文件,它们是否仍将共享给定

这样就不会有任何
错误的多个
定义。同样,使用相同模板调用函数的两个不同的.cpp(例如
incAndShow()
)将共享
myStaticVar
。这正常吗?我之所以问这个问题,是因为我确实依赖于这个“特性”(共享静态变量),我想确定的是,不仅仅是我的实现在做这件事。

这样我才能理解您的问题。您会问,模板函数的每个版本都有自己的myStaticVar实例是否正常。(例如:
incAndShow
vs.
intAndShow
答案是肯定的


您的另一个问题是,如果两个文件包含包含模板函数的头文件,它们是否仍将共享给定T的静态变量。我会说是。

模板将根据需要实例化,这意味着编译器(在本例中也是链接器?)将确保您不会得到同一模板的多个实例以及您需要的模板实例-在您的情况下,只实例化
incAndShow()
,而不实例化任何其他内容(否则编译器将不得不尝试为没有意义的每种类型实例化)

因此,我假设它用于确定实例化模板的类型的相同方法阻止它为同一类型实例化两次,例如,
incAndShow()

这与非模板代码不同。

  • 模板只有在实例化(即使用)后才会真正转化为代码

  • 头不用于实现代码,而仅用于声明
是的,这是“正常的”,但无论您试图用这个“功能”实现什么,都可能有疑问。请尝试解释为什么要使用局部静态变量,也许我们可以想出一种更干净的方法来实现


这是正常的原因,因为模板函数的编译和链接方式获取并查看其自己的incAndShow副本,当程序链接在一起时,两个incAndShow将合并为一个。如果在头文件中内联声明常规函数,将获得类似效果。

您可以依赖此。ODR(一个定义规则)标准中的
3.2/5
,其中
D
表示非静态函数模板(我用草书字体)

如果D是一个模板,并且在多个翻译单元中定义,则上述列表中的最后四项要求应适用于模板定义(14.6.3)中使用的模板封闭范围内的名称,以及实例化点的从属名称(14.6.2).如果D的定义满足所有这些要求,则程序的行为应与D的单一定义相同。如果D的定义不满足这些要求,则行为未定义

在最后四项要求中,最重要的两项要求大致相同

  • D的每个定义应由相同的令牌序列组成
  • 每个定义中的名称应指相同的事物(“实体”)
编辑

我认为单凭这一点还不足以保证不同实例化中的静态变量都是相同的。上面只保证模板的多个定义是有效的。它没有说明由此生成的专门化

这就是链接起作用的地方。如果函数模板专门化(即函数)的名称具有外部链接(
3.5/4
),则引用此类专门化的名称将引用同一函数。对于声明为静态的模板,从其实例化的函数具有内部链接,因为

从具有内部链接的模板生成的实体不同于在其他翻译单元中生成的所有实体。
--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
)从不同的翻译单元,它们将引用相同的功能,这意味着您的静态对象在每种情况下都是相同的。

创建功能模板时的不同之处在于它具有外部链接。所有翻译单元都可以访问相同的白炽显示

从C++标准工作草案N27 98(2008—10-04)释义: 14第4部分:非成员功能模板可以有内部链接,其他功能模板总是有外部链接。 14.8第2点:每个专业都有自己的静态变量副本

template <class T>
void incAndShow()
{
  static int myStaticVar = 0;
  std::cout << ++myStaticVar << " " << std::endl;
}
#include <iostream>

template <class T> class Some
{
public:
   static int stat;
};

template<class T>
int Some<T>::stat = 10;

void main()
{
   Some<int>::stat = 5;
   std::cout << Some<int>::stat   << std::endl;
   std::cout << Some<char>::stat  << std::endl;
   std::cout << Some<float>::stat << std::endl;
   std::cout << Some<long>::stat  << std::endl;
}