c++ - 模板函数内的静态变量

标签 c++ templates static

在 C++ 中,如果在 header.hpp 中定义此函数

void incAndShow()
{
  static int myStaticVar = 0;
  std::cout << ++myStaticVar << " " << std::endl;
}

并且您在至少两个 .cpp 文件中包含 header.hpp。然后你会有multiple definition of incAndShow() .这是预期的。但是,如果您将模板添加到函数中

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

那么你将没有任何multiple definition of错误。同样,使用相同模板(例如 incAndShow<int>() )调用函数的两个不同 .cpp 将共享 myStaticVar .这是正常的吗?我在问这个问题,因为我确实依赖于这个“特性”(共享静态变量),并且我想确保这样做的不仅仅是我的实现。

最佳答案

您可以信赖这一点。 ODR(一个定义规则)在 3.2/5 上说在标准中,D代表非静态函数模板(我的草书字体)

If D is a template, and is defined in more than one translation unit, then the last four requirements from the list above shall apply to names from the template’s enclosing scope used in the template definition (14.6.3), and also to dependent names at the point of instantiation (14.6.2). If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

最后四个要求中,最重要的两个大致是

  • D 的每个定义都应由相同的标记序列组成
  • 每个定义中的名称应指相同的事物(“实体”)

编辑

我认为仅此一项不足以保证您在不同实例中的静态变量都是相同的。以上仅保证模板的多个定义有效。它没有说明由此产生的特化。

这是 linkage 发挥作用的地方。如果函数模板特化(它是一个函数)的名称具有外部链接(3.5/4),那么引用这种特化的名称是指到相同的功能。对于声明为静态的模板,从它实例化的函数具有内部链接,因为

Entities generated from a template with internal linkage are distinct from all entities generated in other translation units. -- 14/4

A name having namespace scope (3.3.6) has internal linkage if it is the name of [...] an object, reference, function or function template that is explicitly declared static -- 3.5/3

如果函数模板没有用静态声明,那么它有外部链接(顺便说一下,这也是我们必须遵循 ODR 的原因。否则,D 不会被多重定义完全没有!)。这可以来自 14/4 (与 3.5/3 一起)

A non-member function template can have internal linkage; any other template name shall have external linkage. -- 14/4.

最后,我们得出的结论是,从具有外部链接的函数模板生成的函数模板特化具有自身的外部链接 3.5/4 :

A name having namespace scope has external linkage if it is the name of [...] a function, unless it has internal linkage -- 3.5/4

3.5/3 解释了当它具有内部链接时对于显式特化提供的函数,以及 14/4用于生成的特化(模板实例化)。由于您的模板名称具有外部链接,因此您的所有特化都具有外部链接:如果您使用来自不同翻译单元的名称( incAndShow<T> ),它们将引用相同的功能,这意味着您的静态对象在每种情况下都是相同的.

关于c++ - 模板函数内的静态变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/994353/

相关文章:

c++ - 运行现有应用程序以更改数据库,好主意吗?

c++ - openCV 输出 SIFT 描述符的类型

c++ - 在函数 C++ 中调用模板函数

java - 多线程访问的静态方法,Java

java - 为什么我们不把所有东西都静态化呢?

c++ - 相当于 boost::file_system::no_check in boost::filesystem V3?

c++ - 将字符串中的每个字符转换为 ASCII

python - 使用 django 模板创建可读的 html

使用 vector/初始化列表的任何类型的 C++11 动态多维数组

c++ - 静态成员变量和方法