为什么有些情况下我可以声明具有常量大小的数组,而其他情况下却不能呢?

6
我正在尝试创建一个包含2D数组和一些成员函数的结构体。
当我写下以下代码时:
struct Board {
    const int BOARDSIZE = 8;

    bool data[BOARDSIZE][BOARDSIZE];
};

我得到了“非静态成员引用必须相对于特定对象”的报错。然而,当我写下以下代码时:

const int BOARDSIZE = 8;

struct Board {
    bool data[BOARDSIZE][BOARDSIZE];
};

或者:

struct Board {
    bool data[8][8];
};

没有错误。我已经搜索过了,但无法弄清楚为什么它不接受一个而接受另一个。我不想将BOARDSIZE声明为全局变量,因为我不希望它在一个大项目中漂浮,但为了灵活性起见,我也不想每次结构体的成员函数需要棋盘大小时都写上8。

有没有一种方法可以有一个表示棋盘大小的局部变量?


2
在你的第一个片段中,BOARDSIZE 是一个非静态成员。也就是说,它与类的实例"绑定"在一起(这就是错误信息的含义)。你可以通过将其定义为 static inline const int BOARDSIZE = 8; 来实现你所需的功能。 - wohlstad
2
在你的第一个代码片段中,BOARDSIZE 是一个非静态成员。也就是说,它与类的一个实例"绑定"在一起(这就是你错误信息的含义)。你可以通过将其定义为 static inline const int BOARDSIZE = 8; 来实现你的需求。 - undefined
一个古老的技巧(来自C语言)是 enum {BOARDSIZE = 8}; bool[BOARDSIZE][BOARDSIZE];。但从技术上讲,BOARDSIZE并不是一个变量 - 它是一个命名的枚举值。 - Peter
数组大小必须是编译时常量,而不仅仅是使用const限定符声明的变量的值。 - user7860670
@Peter 哪个古老的 C 语言有 enums - Swift - Friday Pie
显示剩余5条评论
3个回答

4
当然,一个替代方案是使用静态常量成员变量;就像这样:
struct Board {
    static const int BOARDSIZE = 8;

    bool data[BOARDSIZE][BOARDSIZE];
};

并且最好是constexpr,而不仅仅是const,尽管在这种情况下它们是等价的。const仍然可以在运行时被赋值。 - Swift - Friday Pie
并且最好是constexpr,而不仅仅是const,尽管在这种情况下它们是等效的。const仍然可以在运行时被赋值。 - undefined

1

虽然@Jakub Skop的答案可以完成工作,但我建议你考虑创建Board模板。这将使你的代码更通用,也将增加代码的可重用性。

template<size_t s>
struct Grid {
    int arr[s][s];
};

Grid<8> grid;

不要过于复杂化。如果 OP 想实现象棋(Chess),为什么他们会需要一个除了8x8之外的棋盘呢? - tos-1
不要过于复杂化。如果OP想要实现国际象棋,为什么他们会需要一个不是8x8的棋盘呢? - undefined
@tos-1 你会感到惊讶的,有数十个衍生游戏。 - Swift - Friday Pie

0
您需要一个在编译时评估的表达式。您的选择有:
struct BoardCPP11 {
    static constexpr int BOARDSIZE = 8;  // everywhere will be compile-time

    bool data[BOARDSIZE][BOARDSIZE];
};

struct BoardCPP98 {
    static const int BOARDSIZE = 8;  // it's still a variable

    bool data[BOARDSIZE][BOARDSIZE]; //  but expression can be compile-time
};

struct BoardOldSkool {
    enum { BOARDSIZE = 8 };    // is an non-entity, a name for numeric value

    bool data[BOARDSIZE][BOARDSIZE]; 
};

非静态成员无法工作的原因是因为对象通常会在运行时创建(除非它是一个constexpr,anno C++11)。非静态成员也会在那个时候被创建。在C++11之前,只有整数全局const变量的值、字面量或枚举器可以被视为编译时数组大小的值,这包括静态类成员。
对于模板爱好者来说,
template <unsigned BOARDSIZE>
  struct BoardBase { bool data[BOARDSIZE][BOARDSIZE]; };
  using Board = BoardBase <8>;

模板参数始终是编译时的。我对这种方法有点偏爱,但它会使头文件变得臃肿,并且需要极度小心。新的C++特性,模块,解决了这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接