嗯,一般来说,C++ 模板和 C# 泛型是similar- 与 Java 泛型相比完全地不同,但它们也有很大的差异。与 C# 一样,通过使用反射来获取运行时支持,获取描述用于实例化泛型的类型的对象。 C++ 没有反射,它对类型所做的所有操作都是在编译时完成的。
C# 泛型和 C++ 模板之间最大的区别确实是 C# 泛型进行了更好的类型检查。它们总是受到限制,因为它们不允许在定义泛型时未声明有效的操作。 C# 的首席设计师提出了隐含约束会增加复杂性的原因。我不太熟悉 C#,所以我不能在这里进一步讨论。我会讲一下C++的情况如何,以及如何改进它们,这样人们就不会认为C++的东西都是错的。
在 C++ 中,模板不受限制。如果您在模板定义时执行某个操作,则意味着该操作将在实例化时成功。 C++ 编译器甚至不需要从语法上检查模板的有效性。如果它包含语法错误,则必须在实例化时诊断该错误。在此之前的任何诊断都是实施的纯粹好处。
这些隐含的约束在短期内对于模板设计者来说很容易,因为他们不必关心在模板界面中声明有效的操作。他们给模板的用户带来了负担 - 因此用户必须确保他满足所有这些要求。通常,用户尝试看似有效的操作但失败,编译器会向用户提供数百行有关某些无效语法或未找到名称的错误消息。因为编译器无法知道what特别是首先违反了约束,它列出了错误位置周围涉及的代码路径的所有部分,甚至所有不重要的细节,用户将不得不爬过可怕的错误消息文本。
这是一个基本问题,只需在模板或泛型的接口上声明类型参数必须具有哪些属性就可以解决这个问题。据我所知,C#可以约束参数来实现接口或继承基类。它在类型级别上解决了这个问题。
C++ 委员会早就看到需要解决这些问题,并且很快(可能明年),C++ 也将有一种方法来声明此类显式约束(请参阅时间机器注释如下),如下例所示。
template<typename T> requires VariableType<T>
T f(T a, T b) {
return a + b;
}
编译器在此时发出错误信号,因为所编写的表达式未根据要求标记为有效。这首先有助于模板的设计者编写更多内容正确的代码,因为代码已经在某种程度上进行了类型检查(以及可能存在的情况)。程序员现在可以声明该要求:
template<typename T> requires VariableType<T> && HasPlus<T, T>
T f(T a, T b) {
return a + b;
}
现在,它将编译。编译器通过查看T
作为返回类型出现,自动暗示T
是可复制的,因为使用T
出现在界面中,而不是模板主体中。其他要求使用要求条款进行说明。现在,如果用户使用的类型没有op+
定义的。
C++1x 将需求与类型解耦。上面的内容适用于原始类型和类。从这个意义上说,它们更加灵活,但也相当复杂。规定何时以及何时满足要求的规则很长......您可以通过新规则说以下内容:
template<typename T> requires MyCuteType<T>
void f(T t) { *t = 10; }
然后,打电话f
与int
!只需编写一个概念图即可实现MyCuteType<int>
它告诉编译器如何取消引用 int。在这样的循环中它会变得非常方便:
for_each(0, 100, doSomething());
由于程序员可以告诉编译器 int 如何满足 an 的概念input iterator
,如果您只编写适当的概念图,您实际上可以用 C++1x 编写这样的代码,这实际上并不那么困难。
好吧,就这些了。我希望我能告诉你,模板受到限制并不是那么糟糕,但事实上better,因为编译器现在知道类型之间的关系以及模板内对它们的操作。我什至还没有写过axioms
,这是另一件好事C++1x
' 的概念。请记住这是未来的事情,它还没有发布,但大约会在 2010 年发布。然后我们将不得不等待一些编译器来实现这一切:)
来自“未来”的更新
C++0x 概念是not被接受参加选秀,但在 2009 年底被投票淘汰。太糟糕了!但也许我们会在下一个 C++ 版本中再次看到它?让我们都充满希望吧!