首页 > 解决方案 > 标题中的模板规范问题

问题描述

我必须将一些代码从 Microsoft Visual Studio 编译器移植到 clang。这让我有些紧张。因为我必须确保代码仍然可以用 MVSC 编译/链接。以下代码是不法行为语料库。重要的是,我无法将代码拆分为 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 中编译?

标签: c++templates

解决方案


不要只专门化静态变量,而是专门化整个类。这将允许您制作变量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 使用(获取它们的地址或绑定到它们的引用)。因为那样你的多个定义错误将变成一个未解决的定义错误。


推荐阅读