【问题标题】:Multiple definition gets solved with templates使用模板解决多个定义
【发布时间】:2018-05-07 11:57:14
【问题描述】:

a.hpp:

#pragma once

struct S
{
  static int v;
};
int S::v = 0;

b.hpp:

#pragma once

void addOne();

b.cpp:

#include "b.hpp"
#include "a.hpp"

void addOne()
{
  S::v += 1;
}

main.cpp:

#include <iostream>

#include "a.hpp"
#include "b.hpp"

int main()
{
  S::v = 2;
  addOne();
  S::v += 2;
  std::cout << S::v << std::endl;
}

使用g++ -std=c++14 main.cpp b.cpp &amp;&amp; ./a.out(S::v 的多重定义)编译时不起作用。

但是,当我将代码更改为: a.hpp:

#pragma once

struct S
{
  template<typename T>
  static int v;
};
template<typename T>
int S::v = 0;

并将所有 S::v 替换为 S::v&lt;void&gt; 它编译并按照我希望第一个示例工作的方式工作(输出 5)。

我相信我知道为什么第一个代码示例不起作用:int S::v = 0; 行在main.cpp 单元中编译一次,在b.cpp 单元中编译一次。当链接器将这两者链接在一起时,变量S::v 基本上会被重新定义。(?)

为什么带有模板的代码可以工作?

【问题讨论】:

  • 您可以尝试将int S::v = 0; 移动到a.cpp 看看会发生什么
  • 如果 struct 是模板,这甚至可以在 c++14 之前工作。它只是静态模板变量(和模板方法)的一个属性——允许在不同的翻译单元中进行多个定义。
  • 如果您有 C++17,请在其中粘贴 inline

标签: c++ templates compilation c++14


【解决方案1】:

为什么带有模板的代码可以工作?

基本上,因为标准是这样说的。

对于模板,规则通常是:“每个使用它们的人都必须有他们的定义可用。”这同样适用于类模板的静态数据成员:这种静态数据成员的定义必须存在于使用它的每个翻译单元中。由编译器和链接器来确保这不会导致错误。

请注意,从 C++17 开始,您可以通过使静态数据成员内联来解决非模板情况:

#pragma once

struct S
{
  static inline int v = 0;
};

【讨论】:

  • 这个答案非常简单。例如,就链接而言,显式特化更像非模板,并且仅当模板尚未在另一个 TU 中使用相同参数实例化时才需要此处的变量定义。此外,诸如强符号与弱符号之类的实现细节可能很有趣。我承认我现在懒得写一个不同的答案……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 2018-07-14
  • 1970-01-01
  • 2014-12-26
相关资源
最近更新 更多