我必须将一些代码从 Microsoft Visual Studio 编译器移植到 clang。这让我有些紧张。因为我必须确保代码仍然可以使用 MVSC 进行编译/链接。以下代码是corpus delicti。重要的是,我不能将代码拆分为 src 和头文件。
编译器:6.0.0-1ubuntu2 和 Visual Studio 2015
C++:版本 14
操作系统:Ubuntu 18.04 和 Windows 10/7
代码在头文件中。我将它包含在几个 src 文件中。
代码:
#ifndef GLOBAL_SETTINGS_
#define GLOBAL_SETTINGS_
#include <cstdint>
namespace global {
enum resolution {
Hz,
kHz,
MHz
};
template<resolution T>
struct sys_clk
{
static const double frequency;
};
#define SYS_CLK_FREQ (115.0e6)
template<> const double sys_clk<Hz>::frequency = SYS_CLK_FREQ;
template<> const double sys_clk<kHz>::frequency = SYS_CLK_FREQ/1.0e3;
template<> const double sys_clk<MHz>::frequency = SYS_CLK_FREQ/1.0e6;
#undef SYS_CLK_FREQ
} // namespace global
#endif /* GLOBAL_SETTINGS_ */
这编译得很好,但链接器发现自己无法解决。
链接器错误:
multiple definition of `global::sys_clk_scon<(global::resolution)0>::frequency'
multiple definition of `global::sys_clk_scon<(global::resolution)1>::frequency'
multiple definition of `global::sys_clk_scon<(global::resolution)2>::frequency'
问题:
这个链接器错误是如何解决的,所以它可以在 MVSC 和 clang 中编译?
最佳答案
与其专门化静态变量,不如专门化整个类。这将允许您创建变量 constexpr
,从而消除在任何 TU 中定义它们的需要。
template<resolution T>
struct sys_clk;
#define SYS_CLK_FREQ (115.0e6)
template<> struct sys_clk<Hz> {
static constexpr double frequency = SYS_CLK_FREQ;
};
template<> struct sys_clk<kHz> {
static constexpr double frequency = SYS_CLK_FREQ/1.0e3;
};
template<> struct sys_clk<MHz> {
static constexpr double frequency = SYS_CLK_FREQ/1.0e6;
};
#undef SYS_CLK_FREQ
需要注意的是,您必须确保它们未被 ODR 使用(使用它们的地址或绑定(bind)引用)。因为那时你的多重定义错误将变成一个 Unresolved 定义错误。
关于c++ - header 中的模板规范问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57867155/