【问题标题】:C++ Template specialization for constant variables常量变量的 C++ 模板特化
【发布时间】:2020-06-01 19:35:28
【问题描述】:

我目前正在尝试创建一个专门用于多种类型的模板的编译时常量变量。目前,我正在使用常量表达式,例如以下通用示例:

template<typename T>
constexpr T GENERAL_CONSTANT = T(0.01);

template<> constexpr float GENERAL_CONSTANT<float> = float(0.02);

template<> constexpr double GENERAL_CONSTANT<double> = double(0.03);

然而,此代码似乎只适用于某些编译器/链接器。它将为 Windows 10 的 Clang 9.0.0、Windows 10 的 Clang 6.0.0、Ubuntu 18.04 的 Clang 6.0.0 和 Ubuntu 18.04 的 GCC 正确编译和工作。但是在其他几个配置中给出了类似的多重重新定义错误,例如 Windows 10 上的 Clang 10.0.0 或 Unix 上的 Clang 10.0.0,以及其他一些配置。这些错误通常看起来类似于:

/usr/bin/ld: <some path to a.cpp> multiple definition of `GENERAL_CONSTANT<double>'; <some path to a.cpp>: first defined here
/usr/bin/ld: <some path to a.cpp> multiple definition of `GENERAL_CONSTANT<float>'; <some path to a.cpp>: first defined here

其中 'a.cpp' 是使用常量但未定义它们的文件。因此,鉴于此错误根据编译器和机器而不一致地发生,我很好奇这是否是解决此问题的非标准方法,如果是这样,我应该采取什么方法?

【问题讨论】:

  • 你可以把它包装成一个结构体。
  • 还有,应该是template&lt;&gt; constexpr float GENERAL_CONSTANT&lt;float&gt; = float(0.02);
  • @PiotrSkotnicki 你是对的,我忘了在上面添加模板参数,但在我的代码中已经有了。至于更多细节,变量模板定义在头文件中,常量仅用于实现类/结构的源文件,这些类/结构也按类型模板化,即通常为浮点和双精度。

标签: c++ templates compile-time-constant


【解决方案1】:

const 变量模板的限定(并且constexpr 确实使对象const)不暗示内部链接[basic.link]/p3

具有命名空间范围的名称如果是以下名称,则具有内部链接

  • 显式声明为静态的变量、变量模板、函数或函数模板;或

  • 非易失性const限定类型非模板变量,除非[...]

这似乎是最近的变化(CWG 2387):

2018 年 12 月电话会议的注意事项:

CWG 认为const 类型不应影响变量模板或其实例的链接。

这解释了您在 Clang-10 中观察到的差异。

作为解决方案,将变量模板及其特化标记为staticinline。前者强制内部链接,而后者从一个定义规则中排除变量模板实例,允许多个定义,前提是它们位于单独的翻译单元中。

【讨论】:

  • 很高兴知道,添加 'inline' 关键字似乎对有问题的配置有效。我认为根据您提供的概要,使用“内联”将是我使用的最佳选择。谢谢!
【解决方案2】:

此代码按原样编译。见This Demo。 即使标记为constexpr,专用模板变量仍将编译为二进制文件。由于您在多个翻译单元中使用标头和这些变量,因此您会收到链接器错误。 您可以通过 ld 给您的错误来判断这一点。

标记专业化 inline 将防止这种情况发生并解决问题:

template<typename T>
constexpr T GENERAL_CONSTANT = T(0.01);

template<> inline constexpr float GENERAL_CONSTANT<float> = float(0.02);

template<> inline constexpr double GENERAL_CONSTANT<double> = double(0.03);

这是一个编译器错误,因为 constexpr 暗示 inline 用于变量和函数,但显然,某些编译器版本会为模板专业化而搞砸。

【讨论】:

  • 啊,很高兴知道,添加 inline 关键字似乎已经解决了有问题的配置的问题。感谢您的帮助!
  • 这不是编译器错误。对于非成员变量,constexpr 都没有暗示 inline。您的意思可能是“内部链接”
猜你喜欢
  • 2013-10-07
  • 1970-01-01
  • 2011-06-17
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多