c++ - 使用模板解决多个定义
问题描述
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++17 开始,您可以通过使静态数据成员内联来解决非模板情况:
#pragma once
struct S
{
static inline int v = 0;
};
推荐阅读
- flutter - Flutter / Mac / AndroidStudio / Gradle / appbundle
- php - 如何使另一个计数函数中的计数函数工作
- vaadin - 如何在加载后对 Vaadin 组件进行运行时更改
- .net - 将 log4net 从 2.0.8 降级到 2.0.0 并在代码运行之前获得未处理的异常
- c++ - std::future.wait_for 永远阻塞
- android - 应用程序在启动时崩溃(Lollipop 5.1.1,平板电脑)
- java - 在意图确认过程中如何处理用户更正?
- python - 如何使用python分隔文本和标签
- php - 通过 PHP 从谷歌搜索中仅抓取 1 个结果
- css - 是否可以在 web.CalendarRenderer 中更改颜色?