发布网友 发布时间:2024-08-19 12:46
共1个回答
热心网友 时间:2024-08-22 23:18
在编程语言中,模板有着不同的名称,如Java和C#中的generics,C++和D中的templates。尽管从用户角度来看这些实现的差异不大,主要是语法上的区别。然而,这两种实现方法可以被区分为类型擦除和类型展开。
类型擦除的实现方式中,模板中的类型参数在模板自身内部是不存在的;而类型展开的实现方式中,模板中的类型参数在实现的类型内部存在。类型擦除模板需要类似类型限制,而类型展开模板在编译时无法简单地生成独立的包。下面通过示例详细解释这两种实现。
以类C为例,其基本等同于。
在类型擦除的实现中,编译器会将模板C编译为单独的类C的包,同时包含有限的元数据,比如对于D的类型限制(例如T: new()或T getter())。Java则通过extends和super来实现类似的限制。虽然细节上有所不同,但编译器能够将类C简化为类C的包,再加上类型限制的元数据。
在类型展开的实现中,类C可以使用模板参数T的print()函数,无需任何“限制”。如果类C中的D2没有print()函数,编译会失败。因此,类C可以被认为。
如果类C在其他地方被引用,编译器会生成类C_D2,允许直接调用D2::print()函数,无需额外查找类型信息。然而,这种模板实现无法编译为独立的包,且编译器无法仅通过头文件定义进行模板展开。因此,无法使用#include 实现#include 的功能。
在B2Style中,模板实现分为两个主要部分:模板定义和模板展开。B2Style中的实现采用类型展开方法,支持模板的嵌套,允许模板参数实例化,如整型(如int作为参数)。
实现时,首先进行一些杂项修改,比如将名称和类型名分开,然后修改nlexer和syntaxer的规则文件。模板定义和展开分别在template_template.vb和代码生成器中处理。在处理template_type_name节点时,代码生成器将展开实现嵌入代码,并用包含模板参数类型的新的类名替换模板名称,如将C替换为C_D。
早期实现不支持模板嵌套,通过允许递归调用自身来支持模板嵌套。对于模板参数类型实例化,原理与上述一致,即使得模板参数能够接受类型实例,如整型。
实现中有个小问题,即typedef在BStyle中实现,导致B2Style无法识别C和C实际上为同一类型,从而生成两份代码。若要在B2Style中实现scope.type_alias,此问题可得解决。但该问题对实际效果影响不大,仅影响生成代码的大小和编译时间。