Arrays D中的类数组
我可以在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
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)