C++ 初始化模板类中的静态constexpr成员

C++ 初始化模板类中的静态constexpr成员,c++,c++14,C++,C++14,我很惊讶在这里还没有找到我问题的答案。如果我忽略了它,请随时告诉我 编辑:我收到通知说这可能是 虽然这包含了很多关于类模板化类如何被编译器处理的有用信息,但我仍然找不到关于如何处理类所需的静态常量成员的信息,这些静态常量成员实际上只需要一次就可以用于所有可能的模板实例化 我的用例是一个模板化的浮点数到字符串转换类。单成员函数应该是创建附加si前缀的数字的函数。所以需要一些带有前缀字符的查找数组——这个数组和实际选择的模板化浮点类型无关。我是这样做的: // Float2String.h #inc

我很惊讶在这里还没有找到我问题的答案。如果我忽略了它,请随时告诉我

编辑:我收到通知说这可能是 虽然这包含了很多关于类模板化类如何被编译器处理的有用信息,但我仍然找不到关于如何处理类所需的静态常量成员的信息,这些静态常量成员实际上只需要一次就可以用于所有可能的模板实例化

我的用例是一个模板化的浮点数到字符串转换类。单成员函数应该是创建附加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];
//Float2String.h
#包括
模板
类Float2String
{
公众:
//...
静态标准::带siprefix的字符串(FloatType floatNumber,int numsignificandtights)
{
//缩放数字,将其转换为字符串并计算idx以选择正确的前缀。。。
返回floatnumberscaledConvertedTostring+siPrefixes[idx];
}
私人:
静态constexpr char[11][3]siPrefixes={f”,“p”,“n”,“μ”,“m”,“u”,“k”,“m”,“G”,“T”,“p”};
};
//Float2String.cpp
#包括“Float2String.h”
模板
constexpr char Float2String::siPrefixes[11][3];
当尝试实际使用它时,例如转换双倍数字时,我遇到以下链接器错误:

Error:Undefined symbol 'Float2String<double>::siPrefixes' referenced from:
Error:  Float2String<double>::withSIPrefix(double, int) in Main.o
错误:未定义的符号“Float2String::siPrefixes”引用自:
错误:Main.o中的Float2String::withSIPrefix(double,int)
我在Clang上的Mac OS上,用C++ 14编译了。< /P>
问题:我如何做对?也许用另一种方法可以做得更好?

也许你可以在模板计算之外定义你的siPrefixes。 它不取决于模板类型


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

也许您可以在模板Cals之外定义SIPRefix。 它不取决于模板类型


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

可能重复为什么需要在
.cpp
文件中定义任何内容@Evg虽然您的代码段在godbolt上编译得很好,但在我的机器上,当试图在一个只包含一个源文件的简单命令行项目中编译相同的代码时,它仍然会抛出相同的链接器错误。我习惯于静态成员需要在一个单独的编译单元中定义,这就是为什么我将它们放在一个单独的.cpp文件中。您可以将静态成员变量放在一个只返回它的静态方法中。可能重复为什么您需要在
.cpp
文件中定义任何内容@Evg虽然您的代码段在godbolt上编译得很好,但在我的机器上,当试图在一个只包含一个源文件的简单命令行项目中编译相同的代码时,它仍然会抛出相同的链接器错误。我习惯于静态成员需要在一个单独的编译单元中定义,这就是为什么我将它们放在一个单独的.cpp文件中。您可以将静态成员变量放在一个只返回它的静态方法中。您能否用一个简短的代码示例详细说明您将如何实际实现此解决方案?忘记我回答的第二部分。只需将代码从Float2Type.cc传输到Float2Type.h(此代码:template constexpr char Float2String::siPrefixes[11][3];),如果要将代码保存在.cc文件中,则必须为要使用的每个模板显式实例化siPrefix属性。这就是为什么我会将它导出到.h文件,甚至,如果你不关心siPrefix是私有的,把这个变量带到类之外。你能用一个简短的代码示例详细说明你将如何实际实现这个解决方案吗?忘记我答案的第二部分。只需将代码从Float2Type.cc传输到Float2Type.h(此代码:template constexpr char Float2String::siPrefixes[11][3];),如果要将代码保存在.cc文件中,则必须为要使用的每个模板显式实例化siPrefix属性。这就是为什么我会将它导出到.h文件,甚至,如果您不关心siPrefix是私有的,那么将这个变量带到类之外