【问题标题】:Can a C++ class contain a static const std::array initialized inline in a header file?C++ 类可以在头文件中包含静态 const std::array 内联初始化吗?
【发布时间】:2015-10-18 22:37:27
【问题描述】:

这就是我所拥有的:

struct Foo
{
   static std::array<double, 4> acgt_default_background_frequencies() { return {0.281774, 0.222020, 0.228876, 0.267330}; }
};

但我更愿意不使用函数,而只使用一个变量,如下所示:

struct Foo
{
   static constexpr std::array<double, 4> acgt_default_background_frequencies = {0.281774, 0.222020, 0.228876, 0.267330};
};

我想要编译的东西,但是当我 try to use Foo::acgt_default_background_frequencies 它给出链接器错误“未定义对 `Foo::acgt_default_background_frequencies' 的引用”。

我正在尝试做的事情可能吗?我认为,如果我将值内联为 const,而不是将其隐藏在 .cpp 文件中,并且与函数相比,使用常量而不是函数,我认为对我的标题的读者来说更清楚。 constexpr 的目的不是允许这样的事情吗?如果不可能,为什么不呢?

【问题讨论】:

  • 您的函数方法效率非常低,因为它每次调用时都会复制整个数组。您可以通过将数组设为静态并返回对它的引用来解决此问题。

标签: c++ c++11


【解决方案1】:

您在第二个示例中拥有的是一个static 数据成员的声明,它有一个初始化程序,但是您没有在任何地方提供一个定义。如果您将该成员设为odr-use,则需要进行定义。

要提供定义,请将以下内容添加到您的 .cpp 文件中

constexpr std::array<double, 4> Foo::acgt_default_background_frequencies;

问题中的声明适用于 C++14,但请注意,在 C++11 中,您需要一组额外的花括号,例如

struct Foo
{
  static constexpr std::array<double, AlphabetSize> acgt_default_background_frequencies = {{0.281774, 0.222020, 0.228876, 0.267330}};
};

来自 N3337 的相关标准 §9.4.2/3 [class.static.data]

... 文字类型的static 数据成员可以在类定义中使用constexpr 说明符声明;如果是这样,它的声明应指定一个 brace-or-equal-initializer,其中作为 assignment-expression 的每个 initializer-clause 都是一个常量表达式。 ... 如果该成员在程序中被 odr-used (3.2) 使用并且命名空间范围定义不应包含 initializer,则该成员仍应在命名空间范围内定义。

【讨论】:

  • 最终程序中会有多少个数组副本?
  • 感谢它的工作,但我仍然很困惑为什么 static constexpr std::array&lt;double, 4&gt; 需要在 .cpp 文件中定义而 static constexpr double 不需要。
  • @NeilKirk 只有一个Foo::acgt_default_background_frequencies,就像任何其他静态数据成员一样。
  • @JDiMatteo 如果您对变量进行 odr 使用,那也需要一个。见this。如果您只是打印双精度值,则不构成 odr-use,因此 this 有效。
  • @Praetorian,非常感谢,您的评论与您关于 odr-use 的链接相结合,非常清楚。
猜你喜欢
  • 1970-01-01
  • 2018-05-09
  • 2019-04-15
  • 2016-05-10
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多