【问题标题】:How to use constant in class namespace as the array and template parameters?如何在类命名空间中使用常量作为数组和模板参数?
【发布时间】:2015-01-26 13:47:29
【问题描述】:

我想使用类命名空间中的常量作为静态数组的大小和另一个类中的模板参数。我有跟随错误

// MS VS 2010 C++98
// A.h
class A
{
public:
 const static int someNumber;
};
// A.cpp
#include <A.h>
const int  A::someNumber = 5;

// B.h
#include <A.h>
class B
{
  std::bitset<A::someNumber> btst; // Error! C2975: '_Bits' : invalid template argument 

  double control[A::someNumber];   // Error! C2466: cannot allocate an array of constant size 0
};

我怎样才能避免它们?

【问题讨论】:

  • 我可能理解错了,但错误在哪里?
  • @ForceBru 在代码中...(查看 cmets)
  • 你应该把“;”在 A 类和 B 类之后。
  • 您如何期望B.h 知道A.cpp 中设置的值?
  • 感谢大家的指正。

标签: c++ compiler-errors constants static-members c++98


【解决方案1】:

在 C++98 中,您不能使用 constexpr,因为直到 C++11 才引入。

double control[A::someNumber] 需要在编译时 可评估,并且您的A::someNumber定义 驻留在不同的翻译单元中。这就是你的编译器所抱怨的。

但是您可以使用enum。我从模板元编程中使用的习语中借用了这种技术:

class A
{
public:
    enum {someNumber = 5};
}; /*and note this semicolon*/

【讨论】:

  • const static int someNumber = 5; 呢?
  • 也许您也可以在回答中解释这一点。它是有效的 C++03,不是吗?
  • 不确定:我认为在 C++11 之前你不能在类声明中初始化,然后只能用于某些类型(int 就是其中之一)。
  • @Bathsheba:不,你总是可以初始化整数类型的静态常量(当然在 C++98 中,可能更早,但我的记忆并没有那么远)。 C++11 增加了非静态成员的初始化。
  • @Mike Seymour, MS VS 2010 返回错误,当我尝试写时:const static int someNumber = 5; 所以@Bathsheba 是对的。
【解决方案2】:

您的问题并不简单,因为如果您将所有声明放在一个文件中,它将正确编译和运行。

但只要看看编译器在编译 B.h 时能看到什么(假设它包含在 main.cpp 或 B.cpp 中):

#include "A.h" : 好的,它包含 const static int someNumber; someNumber 是一个 const int,它的值将在链接时给出

std::bitset&lt;A::someNumber&gt; btst :好的 bitset,大小是 A::someNumber,它被声明为一个 const int,直到这里都很好......但是哇,当时编译器不知道 const 的值!假设它是 0 => 你会得到这两个错误,因为编译器无法知道 A::someNumber 的未来值!

现在我们知道了,解决方法很简单:只需在 A.h 中写入即可:

const static int someNumber = 5; // valid for a litteral const

因为现在编译器在编译时就知道A::someNumber的值,可以正确编译包含B.h的文件。

编辑

您可能对在A.h 中写入const static int someNumber = 5; 的想法感到害怕,因为它可能包含在许多编译单元中,并且您不想定义在许多单元中相同的常量。但其实这不是问题:

  • 在编译时,编译器会在任何需要的时候使用A::someNumber 的值。它注意到 A 类包含 一个 名为 someNumber 的静态字段。
  • 在链接时,链接器确保只有一个A::someNumber 实例。您可以通过打印来自不同编译单元的静态 const 字段的地址来控制它,您将获得相同的值......除非您的开发工具严重损坏!

【讨论】:

  • 这是正确的(加一),但在任何 MSVS2012 之前的编译器上都会失败(我认为),因为它们没有正确实现标准。
  • @Bathsheba :我刚刚在 MSVC 2008 上尝试过,它工作正常,甚至是静态 const int 的地址部分。但我没有更旧的东西要测试;-)
  • @SergeBallesta,我完全不明白。在编译时,对 class::constant 的引用不是替换为它的地址,而是替换为它的值,因此在编译时它的值是 0。但只有在链接它的值之后才会启动。那么,什么适用于 MS VS 2008?如果我也将 class::const 的初始化添加到 B 编译单元,则会出现错误 C2374: redefinition;多次初始化。
  • @SergeBallesta,哦,对不起,谢谢。我明白了。将值赋值给 class::constants 仅适用于 int。
猜你喜欢
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-18
  • 1970-01-01
  • 2018-08-26
相关资源
最近更新 更多