在我的D程序中,我有一个固定长度的只读数组,我希望用枚举类型索引数组。
如果我做的话
static const my_struct_t aray[ my_enum_t ] = ... whatever ...;
my_enum_t index;
result = aray[ index ];
然后GDC生成的代码非常庞大,在对数组进行索引时会调用运行时。因此,看起来数组被视为可变长度或关联数组(哈希表)或其他东西,无论如何远离具有简单索引的固定长度的轻量级C风格数组。由于枚举具有固定的基数并且无法增长,并且我有一个适度的稀疏值范围(我不会滥用关键字枚举只是为了定义一组随机常量),所以我不知道为什么会发生这种情况。 / p>
我通过将行更改为
来解决问题static const my_struct_t aray[ my_enum_t.max + 1 ]
据我理解,这意味着方括号中的值只是整数类型的已知常数。由于索引现在根本不是枚举,我现在有一个由整数索引的数组,所以我丢失了类型检查,我可以使用任何随机整数类型变量对其进行索引,而不是确保只有正确的(强)类型是使用
我该怎么办?
在更一般的情况下,(愚蠢的例子)
static const value_t aray[ bool ] = blah
例如,我有一个语义上非常合理的索引类型,但不仅仅是无类型的size_t / int / uint我认为我会遇到同样的问题。
我不想说这是编译器设计问题。这肯定是次优行为的一个例子。但为了公平对待编译器究竟是什么告诉它数组是固定长度还是可变,稀疏或密集?我想要两件事;类型检查索引和非可变长度。实际上,在这种特殊情况下,数组是const(我也可以放置不可变的),所以它显然不能以任何方式变长。但是对于具有可修改内容但具有固定长度的数组,您需要能够声明它是固定长度的。
答案 0 :(得分:2)
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);
或者,当然,您不需要将其设置为静态,也可以执行常规实例,并初始化内部等内容。
答案 1 :(得分:1)
在D中,静态和动态数组都由size_t
索引,就像它们在C和C ++中一样。而且你不能在C或C ++中更改D中索引的类型。因此,在D中,如果在数组声明中的括号之间放置一个类型,则定义关联数组而不是静态数组。如果你想要一个静态数组,你必须提供一个整数文字或编译时常量,并且没有办法要求一个裸的静态数组被一个基类型为size_t
的枚举类型索引或者隐式转换为size_t
的类型。
如果要求静态数组使用size_t
以外的类型进行索引,则需要将其包装在结构或类中,并通过成员函数控制对静态数组的访问。您可以重载opIndex
以获取枚举类型并将结构类型视为静态数组。因此,效果应该是有效的,你想要将枚举类型放在静态数组声明中,但它将是成员函数,它接受枚举值并用它调用静态数组而不是对它做任何事情静态数组本身。