【问题标题】:Initialize a static constexpr member in templated class在模板类中初始化一个静态 constexpr 成员
【发布时间】:2018-09-25 16:43:42
【问题描述】:

我很惊讶这里还没有找到我的问题的答案。如果我忽略了,请随时指出我那里。

编辑:我收到通知说这可能与Why can templates only be implemented in the header file? 重复 虽然这包含很多关于编译器如何处理类模板类的有用信息,但我仍然没有找到关于如何处理类所需的静态常量成员的信息,这些成员实际上只需要一次用于所有可能的模板实例化。

我的用例是一个模板化的浮点数到字符串的转换类。一个成员函数应该是创建附加 si 前缀的数字的函数。因此需要一些带有前缀字符的查找数组——这个数组与实际选择的模板浮点类型无关。我做了类似的事情:

// Float2String.h
#include <string>

template <typename FloatType>
class Float2String 
{

public:

    //...

    static std::string withSIPrefix (FloatType floatNumber, int numSignificantDigits)
    {
         // scale the number, convert it to a string and compute the idx to pick the right prefix...

         return floatNumberScaledAndConvertedToString + siPrefixes[idx];
    }

private:
    static constexpr char[11][3] siPrefixes = {"f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P"};
};

// Float2String.cpp
#include "Float2String.h"

template <typename FloatType>
constexpr char Float2String<FloatType>::siPrefixes[11][3];

当尝试实际使用它时,例如要转换双数,我收到以下链接器错误:

Error:Undefined symbol 'Float2String<double>::siPrefixes' referenced from:
Error:  Float2String<double>::withSIPrefix(double, int) in Main.o

我在 Mac OS 上使用 Clang 并启用 C++ 14 进行编译。

问题:我该如何做?也许用不同的方法可以做得更好?

【问题讨论】:

  • 为什么需要在.cpp 文件中定义任何内容? godbolt.org/z/MLUmDm
  • @Evg 虽然您的代码 sn-p 在 Godbolt 上编译得很好,但当尝试在仅包含一个源文件的简单命令行项目中编译相同的代码时,它仍然会在我的机器上引发相同的链接器错误。我习惯静态成员需要在单独的编译单元中定义,这就是为什么我将它们放入单独的 .cpp 文件中
  • 你可以把你的静态成员变量放在一个只返回它的静态方法中。

标签: c++ c++14


【解决方案1】:

也许您可以在模板类之外定义您的 siPrefixes。 它不依赖于您的模板类型。

您可以直接在您的 cpp 文件中定义它,也可以在您的 cpp 文件中使用 SIPrefix 实现移动方法。

【讨论】:

  • 您能否通过一个简短的代码示例详细说明您将如何实际实施此解决方案?
  • 忘记我回答的第二部分。只需将代码从 Float2Type.cc 转移到 Float2Type.h(此代码:template constexpr char Float2String::siPrefixes[11][3];)如果您想将代码保留在 .cc 文件中您必须为您将使用的每个模板显式地实例化您的 siPrefix 属性。这就是我将它导出到 .h 文件的原因,即使你不关心 siPrefix 是否是私有的,也可以将此变量放在类之外
猜你喜欢
  • 2021-08-07
  • 1970-01-01
  • 1970-01-01
  • 2016-03-10
  • 1970-01-01
  • 2011-03-14
  • 2017-01-15
相关资源
最近更新 更多