在C ++中,我可以在编译时实例化泛型类型,然后在运行时构造它:
struct Vertex {};
struct Edge {};
template<typename NodeType, typename IdType>
struct Wrapper {
IdType id;
Wrapper(IdType id) : id{id} {};
};
int main() {
using vertexWrapper = Wrapper<Vertex, int>;
vertexWrapper v(3);
}
变量清楚地分开,类型看起来/感觉不像值。我想在Chapel做类似的事情:
record Vertex {}
record Edge {}
record Wrapper {
type nodeType;
type idType;
var id: idType;
proc init(id) {
this.id = id;
}
}
type vertexWrapper = Wrapper(Vertex, int);
var v1 = 3: vertexWrapper;
当我编译这段代码时,我得到:
chpl -o graph-add-inclusion --cc-warnings test.chpl
test.chpl:9: In initializer:
test.chpl:10: error: can't omit initialization of field "nodeType", no type or default value provided
test.chpl:10: error: can't omit initialization of field "idType", no type or default value provided
有没有办法将类型构造与Chapel中的值构造分开,以实现标记类型的效果,因为我试图进入我的示例?我使用标记类型来实现两种实体(这里是顶点和边)常见的单一实现,但我希望这些实体是不同的类型。
还有一个相关的问题。我应该只写:
type vertexWrapper = Wrapper(Vertex);
然后从我的构造函数中分别推导出整数?
似乎在定义时检查构造函数,但没有可能与值分开提供类型。我是否做到了这一点,如果我做到了,这件事情将来会改变吗?
答案 0 :(得分:4)
您遇到的问题是您定义的初始值设定项,而不是您使用的类型别名。由于你如何定义它,用户可以想象写这个:
var x = new Wrapper(1); // type is inferred from the new's return
并且初始化器不知道如何处理nodeType和idType字段。因此,您的初始化程序需要在其正文中明确设置它们。
我同意初始化程序在使用实例化时弄清楚它们的值会很好,并且预计这将是我们将来支持的内容。在短期内,你可以通过一些重复的工作获得你想要的东西。
要做到这一点,首先你可以更新初始化程序,以便它可以根据相应的参数找出idType。
proc init(id) {
idType = id.type;
this.id = id;
}
但是,这对nodeType字段没有帮助,因为初始化程序在您所描述的内容中没有相应的值字段。这意味着您必须手动将其提供给初始化程序。您可以通过访问其nodeType字段以一般方式从类型别名执行此操作:
var v1 = new vertexWrapper(vertexWrapper.nodeType, 3);
但是您还需要更新初始化程序以将其作为参数。因此,创建实例v1必须看起来像这样:
record Vertex {}
record Edge {}
record Wrapper {
type nodeType;
type idType;
var id: idType;
proc init(type nodeType, id) {
this.nodeType = nodeType;
this.idType = id.type;
this.id = id;
}
}
type vertexWrapper = Wrapper(Vertex, int);
var v1 = new vertexWrapper(vertexWrapper.nodeType, 3);
希望这是一个适用于您的用例的解决方案。
我应该只写:
type vertexWrapper = Wrapper(Vertex);
然后从我的构造函数中分别推导出整数?
我们目前不支持部分实例化,因此Wrapper(Vertex)
不是您可以编写的内容。如果要将idType设置为像int这样的公共值,可以将其作为类型字段的默认值提供:
type idType = int;
允许您只通过Wrapper(Vertex)
指定nodeType,但这意味着idType被锁定为int,除非您使用new(var x = new Wrapper(Vertex, 3.0);
)创建实例化,或者除非您在其中指定其他内容与nodeType同时发生。
答案 1 :(得分:1)
作为这个答案的序言(正如我对这个问题的评论中所指出的),我认为Chapel的初始化器故事应该改进,以支持初始化器调用代表实例化泛型的类型别名,就像你想要做的那样。
在此之前,我尝试的这个想法似乎有效 [Try It Online]。基本上,我正在使用类型方法 -ie在newNode()
类型本身上创建一个工厂方法Wrapper
,一个在类型本身而不是在类型上调用的方法该类型的值:
record Vertex {}
record Edge {}
record Wrapper {
type nodeType;
type idType;
var id: idType;
proc type newNode(id) {
return new Wrapper(nodeType, idType, id);
}
}
type vertexWrapper = Wrapper(Vertex, int);
var v1 = vertexWrapper.newNode(3);
writeln(v1);
由于vertexWrapper
类型别名已定义nodeType
,我可以在工厂方法中引用它,以便创建Wrapper
的新实例。
我认为这可以被视为封装Lydia之前提出的解决方案的另一种方式。