首页 > 解决方案 > 使用模板解决多个定义

问题描述

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;
}

主.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 && ./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<void>编译和工作我打算如何工作的第一个例子(输出5)。

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

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

标签: c++templatescompilationc++14

解决方案


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

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

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

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

#pragma once

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

推荐阅读