Arrays D中的类数组

Arrays D中的类数组,arrays,oop,pointers,reference,d,Arrays,Oop,Pointers,Reference,D,我可以在D中创建一个类数组吗?比如: interface A {} class AA: A {} class AB: A {} class AC: A {} ClassList!A list = new ClassList!A {AA, AB, AC}; void testf(ulong testv) { A a = new list[testv]; } 是的,这是可能的,但不一定就是你在那里的方式。可以使用类型元组创建类型列表: import std.typetuple; ali

我可以在D中创建一个类数组吗?比如:

interface A {}
class AA: A {}
class AB: A {}
class AC: A {}

ClassList!A list = new ClassList!A {AA, AB, AC};

void testf(ulong testv) {
    A a = new list[testv];
}

是的,这是可能的,但不一定就是你在那里的方式。可以使用类型元组创建类型列表:

import std.typetuple;
alias list = TypeTuple!(AA, AB, AC);
但是,您不能在运行时将其作为数组进行索引;尝试
新建列表[n]
将是编译时错误。相反,您将创建一个helper函数,在其上循环并返回实例,如下所示:

foreach(index, type; list)
    if(index == testv) {
        a = new type();
        break;
    }
bool checkClassList(Base, T...)() {
   foreach(t; T) {
     static if(!is(t : Base))
         static assert(0, t.stringof ~ " is not a child of " ~ Base.stringof);
   }
  return true;
}

template ClassList(Base, T...) if(checkClassList!(Base, T)) {
    alias ClassList = T;
}
编译的方式是
foreach(foo;compile\u time\u list)
实际上变成了一个大的展开循环。生成的代码就像您编写的:

if(0 == testv) { a = new AA(); goto end; }
if(1 == testv) { a = new AB(); goto end; }
if(2 == testv) { a = new AC(); goto end; }
end:
因此,这适用于运行时值,弥补了编译时列表和所需数组索引之间的差距

值得注意的是,这并不一定是最有效的,但除非你的类列表中有上千个条目,否则我怀疑这是否重要。提高速度的另一个选择是在编译时从列表中生成一个switch语句,然后将其混合在一起。switch语句将编译为更高效的查找表。但可能性是简单的循环是好的

总之,综合起来,我们得到:

import std.stdio;

interface A {}
class AA: A {}
class AB: A {}
class AC: A {}

import std.typetuple;
alias list = TypeTuple!(AA, AB, AC);

void testf(ulong testv) {
  A a;
  foreach(index, type; list)
    if(index == testv) {
    a = new type();
        break;
}

  if(a is null)
      writeln("bad type index");
  else {
      writeln(typeid(cast(Object) a), " was created");
  }
}

void main() {
    testf(0);
    testf(1);
    testf(2);
    testf(3);
}
结果:

$ ./test50
test50.AA was created
test50.AB was created
test50.AC was created
bad type index
这正是我们想要的

顺便说一句,
typeid(cast(Object)a)
可能看起来很奇怪,它正在获取类型的动态类。它必须首先强制转换到对象,否则将打印接口名。由于D接口不一定是D类(它们也可以是COM对象或C++类),所以Type ID并不总是可用的。cast-to对象确保它是一个D类,从而获取运行时类型的详细信息

编辑:我看到你在新闻组上也要求检查循环中的基类。以下是如何做到这一点:

您可以为它编写自己的元组模板,或者让 工厂函数编译失败:A=new T();意志 如果A不是t的基类或接口,则失败

将支票放入列表可能如下所示:

foreach(index, type; list)
    if(index == testv) {
        a = new type();
        break;
    }
bool checkClassList(Base, T...)() {
   foreach(t; T) {
     static if(!is(t : Base))
         static assert(0, t.stringof ~ " is not a child of " ~ Base.stringof);
   }
  return true;
}

template ClassList(Base, T...) if(checkClassList!(Base, T)) {
    alias ClassList = T;
}
用法:

alias list = ClassList!(A, AA, AB, AC); // good
加:

和获取错误:

test50.d(12): Error: static assert  "B is not a child of A"
test50.d(19):        instantiated from here: checkClassList!(A, AA, AB, AC, B)