由枚举索引的 D 直数组

D straight array indexed by an enum

在我的 D 程序中,我有一个固定长度的只读数组,我希望通过枚举类型对该数组进行索引。

如果我做类似的事情

static const my_struct_t aray[ my_enum_t ] = ... whatever ...;

my_enum_t index;

result = aray[ index ];

然后 GDC 生成的代码非常庞大,在对数组进行索引时充满了对运行时的调用。所以它看起来好像数组被视为可变长度或关联数组(散列 table)或其他东西,无论如何远离具有直接索引的固定长度的轻量级 C 样式数组。由于枚举具有固定的基数并且不能增长,并且我的值范围适度稀疏(我没有滥用关键字 enum 只是为了定义大量随机常量)所以我不知道为什么会这样。

我通过将行更改为

解决了这个问题
static const my_struct_t aray[ my_enum_t.max + 1 ]

据我了解,这意味着方括号中的值只是一个已知的整型常量。由于索引现在根本不是枚举,我现在有一个由整数索引的数组,所以我丢失了类型检查,我可以用任何随机整数类型的变量对其进行索引,而不是确保只有正确的(强)类型是使用过。

我应该做什么?

在更一般的情况下,(愚蠢的例子)

static const value_t aray[ bool ] = blah

例如,我有一个在语义上完全合理的索引类型,但不仅仅是无类型的 size_t/int/uint 我想我会遇到同样的问题。

我不想说这是一个编译器设计问题。这肯定是次优行为的情况。但为了公平起见,究竟是什么告诉编译器数组是固定长度的还是可变的,是稀疏的还是密集的?我想要两件事;索引和非可变长度的类型检查。实际上,在这种特殊情况下,数组是 const(我也可以把 immutable 放好)所以它显然不能以任何方式变长。但是对于具有可修改内容但长度固定的数组,您需要能够声明它是固定长度的。

V[K] name 是关联数组的语法,它确实执行运行时调用等,即使类型仅限于少量值,如 bool 或枚举。编译器可能 可以 优化它,使它像 AA 一样对程序起作用,同时将它实现为一个简单的固定长度数组,但它没有;它对所有键类型都一视同仁。

我建议按照您开始的方式进行操作:T[enum.max + 1],但如果您想强制类型安全,则进行包装。如果你只想要它的一个实例,你可以将索引重载设为静态:

enum Foo {
        one,
        two
}

struct struct_t {}

struct array {
        static private struct_t[Foo.max + 1] content;
        static struct_t opIndex(Foo idx) { return content[cast(int) idx]; }     
}

void main() {
        struct_t a = array[Foo.one];
}

然后,如果您想要更简单的重用,您可以将其通用化。

struct enum_array(Key, Value) {
        static private struct_t[Key.max + 1] content;
        static Value opIndex(Key idx) { return content[cast(int) idx]; }
}

alias array = enum_array!(Foo, struct_t);

或者,当然,你不需要让它成为静态的,你也可以做一个普通的实例,然后初始化里面的内容等等。

在 D 中,静态和动态数组都由 size_t 索引,就像它们在 C 和 C++ 中一样。与在 C 或 C++ 中一样,您不能在 D 中更改索引的类型。因此,在 D 中,如果您在数组声明的括号之间放置一个类型,则您定义的是关联数组而不是静态数组。如果你想要一个静态数组,你必须提供一个整数文字或编译时常量,并且没有办法要求一个裸静态数组由具有 size_t 或基本类型的枚举类型索引隐式转换为 size_t.

的类型

如果你想要求你的静态数组由size_t以外的类型索引,那么你需要将它包装在结构或class中并控制对静态数组的访问通过成员函数。您可以重载 opIndex 以获取您的枚举类型并将您的结构类型视为静态数组。因此,效果应该实际上是您将枚举类型放入静态数组声明中时试图做的事情,但是成员函数会采用枚举值并使用它调用静态数组,而不是对静态数组本身。