从C++到.NET:将模板映射到泛型

本文配套源码

讨论 ISO-C++ 文本查询语言 (TQL) 应用程序到 Microsoft .NET Framework 和 C++/CLI 的转换。特别是,我将深入讨论如何将模板和标准模板库 (STL) 映射到 .NET 泛型工具。尽管在 1991 年,我曾在贝尔实验室从事过 Cfront 3.0 版的最初模板实现,并曾极力提倡使用这些模板,但我建议不要在 C++/CLI 中使用模板。

在 .NET 下,C++ 模板实例化的静态特性使其无法成为 C++/CLI 的“一等公民”。在语言设计中,我们说主要语言实体都要具有“一等公民”身份。以 Int 为例:19 世纪 70 年代,建立抽象数据类型的运动尝试提供某种机制,使用户定义类型能够接近原始语言类型(例如 Integer)的“一等公民”身份。因此,对语言的“一等公民”和“二等公民”进行比较始终是一种合理的方法。如果我们在 .NET Framework 下对泛型对象和模板对象进行比较,就会发现泛型为“一等公民”,而模板不但排名靠后,而且排在最后一位,因此它们不再是您的最佳选择。

问题在于模板对于其所在的程序集来说为本地对象。这是因为程序集类型不是简单地按其名称来标识,而是按其位置来标识。这样,方法中在程序集之间传递的 myTemplate<int> 的两个对象将被标记为类型错误。因此模板不能作为类型的公共接口的一部分。此外,模板不具有语言互操作性。

泛型紧密集成在 .NET 中,因为对底层中间语言进行了扩展以支持泛型。此外,运行库可以根据需要自动按需管理泛型的实例化。在本机编译模型中,文件是分别进行编译的,只是在运行时才链接在一起。由于本机编译模型的特性,在 C++ 中一直未解决该问题。

一般来说,.NET 解决了 C++ 中因本机编译模型的原因而无法解决的三个大规模编程问题:复杂全局对象的初始化顺序(即,当对象的使用和初始化在不同文件中分别进行时,确保在首次使用对象前构造该对象)、动态堆分配内存的管理以及参数化类型的按需实例化。这些问题中的每个问题都代表了实际域解决方案中与复杂性无关的一个语言层。在 .NET 下,这些问题不复存在。

由于 TQL 在很大程度上依赖于模板(特别是依赖于 STL),因此模板与泛型的问题也就成了本专栏讨论的重点。有三个要解决的主要问题,它们都非常令人头痛,因为这些工作都是我们所不想做的。

首先,我的实现使用了 STL Vector 类。虽然在 C++/CLI 下 STL 当前不可用,但 .NET Framework 提供了一个等价泛型集合类型:List<T>。随后,我只需在声明中替换成该类即可。不过,我必须手动更改每个对象的用法,因为这两组操作是不相同的。(此外,我可以考虑编写自己的 Vector 类的一对一映射。我将在后面考虑对 STL 集合关联容器使用此方法。)例如,下面列出了一些 Vector 声明:

typedef pair<short,short> location;
typedef vector<location> loc;
typedef vector<string>  text;
typedef pair<text*,loc*> text_loc;

若要将 Vector 替换为 List,只需打开命名空间,更改类型名称,然后添加跟踪句柄 (^) 即可,因为 List 是一个引用类:

using namespace System::Collections::Generic;
typedef pair<short,short> location;
typedef List<location>^  loc;
typedef List<String^>^  text;
typedef pair<text,loc>  text_loc;

其次,就像您在上面的代码示例中看到的那样,本实现还使用了 C++ 标准库 Pair<> 工具。该工具对于 C++/CLI 不可用,因此我必须在此处执行一些操作。由于这是一个非常简单的实现,因此我只需看一下是否能够克隆它就可以了。结果是,在本机平台和托管平台之间不存在任何纯粹的一对一映射。而且,这也没有什么好奇怪的,因为在考虑如何使本机平台更高效运行时,您需要将托管平台视为最佳选择。(我想现在唯一未考虑到的事项应为是否能提供同样的性能。)

最后,我的实现还使用了 STL Set 类。但很可惜,没有等价的泛型集合类型,因此我必须执行一些操作。我的第一个想法是实现其接口的一对一映射,只是在 .NET Framework 下我无法拦截堆分配。不过,正如您将看到的那样,实践证明这并不是一个好主意。以下是 Set 的 TQL 使用示例:

class Query {
public:
// ...
private:
set<short>*    vec2set( const vector<location>* );
vector<location> loc;
set<short>    *solution;
};

时间: 2024-08-04 10:42:51

从C++到.NET:将模板映射到泛型的相关文章

VO对象通过groovy模板映射XML文件

介绍     之前写过JAVA+XSLT相关的技术博客,最近研究了一个开源工具包org.codehaus.groovy,处理VO对象和XML文件映射非常方便.简言之:将VO对象中的属性(包括Collection, Map),通过groovy模板,映射XML文件. Maven pom.xml <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifa

Spring MVC 基于URL的映射规则(注解版)

好几天没有跟进Spring MVC的学习了,之前看了点源码都忘的差不多了.这次就跟着之前的问题,继续总结下Spring MVC中的小知识. 关于SpringMVC的小demo可以参考这里! url-pattern 如果看过前一篇入门的帖子,应该了解到spring mvc在启动前必须要在web.xml中配置servlet,这样才能拦截到想要映射的url地址. <servlet> <servlet-name>SpringMVC</servlet-name> <serv

C++中函数模板(function template) 详解

C++的模板(template)是泛型编程(generic programming)的基础; 面向对象编程 是 运行(run time)时 知道类型(type); 泛型编程 是编译(compilation) 知道类型; 函数模板(function template)包含模板参数列表(template parameter list); 每个参数类型之前必须包含关键字typename或class, 尽量使用typename, 表达意思更加明确; 非类型模板参数(Nontype Template Pa

(一〇六)函数模板

函数模板的意义在于,可以在不同的参数下,起到同样的作用. 按照教程所说,它们使用泛型来定义函数,其中泛型可用具体的类型(如int.double)替换.通过将类型作为参数传递给模板,可使编译器生成该类型的函数.   由于模板允许以泛型(而不是具体的类型)的方式编写程序,因此在有时也会被称为是通用编程.   由于类型是用参数表示的,因此模板特性有时也被称为参数化类型.   格式: template <typename xx> void 函数名(xx &a, xx &b) { xx

泛型和模板设计模式

当两个或多个功能很大一部分实现都一样,只有其中一部分处理逻辑不同的情况下.我们通常都会采用模板设计模式来实现,这样既可以满足功能的需求也可以很好地实现代码的维护.这也正是设计模式的精髓所在.但是,如果有这样一个需求,该如何实现呢?既满足了模板设计模式的条件,也就是说两个或多个功能的总体实现流程是一致的,只是部分处理逻辑上存在差异:但有点特别的是根据不同的功能,返回值类型有所差别.这样的情况下我们可以通过模板设计模式结合泛型来很好地实现相应的功能. 技术要点 我们先来看下模板设计模式的技术点,模板

《ELK Stack权威指南(第2版)》一导读

Preface前 言 <ELK Stack权威指南>第1版面世之后的这一年多时间里,ELK Stack在Elastic.co公司以及社区的共同努力下飞速发展.国内外都出现了不少基于ELK Stack实现的日志分析产品和创业公司.ELK Stack已经成为DevOps技术栈中必不可缺少的一个部分,较大型的互联网公司甚至已经配备有专职的ELK Stack管理团队. 对于并不精通ELK Stack技术及其发展历史的人来说,过去复杂的版本对应是新手的第一道门槛.最近全新更新的ELK Stack各组件,

剖析C# 2.0泛型类的创建和使用

"一次编码,多次使用",这就是引入泛型的根源.在以前的C++中称为模板,C#泛型通过算法和数据结构支持独立编码.例如,泛型列表意味着,你不必再重写一个强类型集合.在本文中,作者将向你展示定义和使用泛型是多么容易的事情-请注意,长期以来泛型一直被认为是最高级和最困难的术语. 一. 简介 泛型现在在任何一种语言中都被认为是一个高级的强有力的术语.当我在C++中第一次接触模板时,我对之有些疑惑.之后,我读了Bjarne Stroustrop的<The Design and Evolut

C# 编程语言的未来功能 2

编程 声明约束在 C# 中,程序可以为泛型类中声明的每个类型参数提供可选约束列表.约束表示要将一个类型构造成泛型所必须满足的要求.可以使用 where 关键字声明约束,该关键字后跟"参数-要求"对,其中"参数"必须是泛型中定义的某个参数,"要求"必须是类或接口. 为了满足在 Dictionary 类中使用 CompareTo 方法的需要,程序可以对 KeyType 类型参数添加约束,要求传递给 Dictionary 类作为第一个参数的任何类型都必

C#中的泛型 (From dotNet SDK 2.0 Beta1)

泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性.泛型为.NET框架引入了类型参数(type parameters)的概念.类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明.实现.这意味着使用泛型的类型参数T,写一个类MyList<T>,客户代码可以这样调用:MyList<int>, MyList<string>或 MyList<MyClass>.这避免了运行时类型转换或装箱操作的代价和风