c# - 是什么使模板与通用模板不同?

标签 c# java c++ templates generics

我了解C++中模板的方面与Java和C#中的泛型不同。 C#是一种形式,Java使用类型擦除,C++使用鸭子类型,等等。C++模板可以做很多事情,而Java和C#泛型则做不到(例如,模板特化)。但是Java泛型可以做很多事情,而C#和C++则做不到(例如,使诸如class Foo<T extends Comparable<?>>这样的泛型族的有界类型参数),而C#泛型可以做很多事情,而Java和C++则做不到(例如,运行时通用反射)。 [编辑:显然Java泛型比我想象的要弱得多。 (这是在说些什么。)无论如何,尽管它们无能为力,但它们仍与C#的泛型一起被视为泛型。]

我不明白的是,概念上使模板与泛型不同的是什么。 C++模板的哪些部分是非模板但不能通用的,无法完成的工作?例如,如果我要实现一种支持模板的语言,那么其中绝对需要包含什么?对于该语言支持泛型而言,我有什么遗漏之处?

我的猜测是模板是泛型的超集,或者它们是实现泛型的一种方式,但是我真的不明白是什么将真正的模板与真正的泛型区分开。

最佳答案

嗯..如果您说您深入理解C++模板,并说您看不到/感觉不到泛型和它们之间的区别,那么,很可能您是对的:)

有许多差异将描述泛型如何/为什么比模板更好,列出大量差异等,但这与该思想的核心无关。

想法是允许更好的代码重用。模板/泛型为您提供了一种构建某种高阶类定义的方法,该类定义对某些实际类型进行抽象。

用这个术语,它们之间没有区别,唯一的区别是那些由特定功能和底层语言和运行时约束所强制的区别。

有人可能会争辩说,泛型提供了一些额外的功能(通常是在谈论对象的类树的动态自省(introspection)时),但是其中很少(如果有的话)无法在C++模板中手动实现。尽力而为,它们中的大多数都可以实现或仿真,因此它们不能很好地区分“适当的泛型”和“真实的模板”。

其他人会争辩说,由于C++的复制粘贴行为,可获得的巨大的优化潜力就是两者之间的差异。对不起,不是真的。 Java和C#中的JIT几乎也可以做到,但是做得很好。

然而,有一件事确实可以使Java/C#的泛型成为C++模板功能的真正子集。您甚至提到了它!

这是模板专门化

在C++中,每个特化行为都表现为完全不同的定义。

在C++中,专门用于T == int的template<typename T> Foo可能看起来像:

class Foo<int> 
{
    void hug_me();

    int hugs_count() const;
}

而专门用于T == MyNumericType的“相同”模板可能看起来像
class Foo<MyNumericType> 
{
    void hug_me();

    MyNumericType get_value() const;
    void  reset_value() const;
}

仅供引用:那只是伪代码,不会编译:)

Java和C#的泛型都无法做到这一点,因为它们的定义表明所有泛型类型实现将具有相同的“用户界面”。

更重要的是,C++使用SFINAE规则。模板可能存在许多“理论上相撞”的专业定义。但是,在使用模板时,仅使用那些“实际良好”的模板。

如果使用与上面的示例类似的类,请使用:
 Foo<double> foood;
 foood.reset_value();

仅使用第二个特化,因为由于缺少“reset_value”,第一个特化无法编译。

使用泛型,您将无法做到这一点。您需要创建一个具有所有可能方法的通用类,然后在运行时动态检查内部对象,并对不可用方法抛出一些“未实现”或“不支持”的异常。那太可怕了。这样的事情在编译时应该是可能的。

模板特化 SFINAE 的实际功能,含义,问题和整体复杂性才是真正区分泛型和模板的地方。简而言之,泛型是以这样的方式定义的,即不可能进行专门化,因此不可能进行SFINAE,因此,自相矛盾的是,整个机制更容易/更简单。

在编译器内部更容易/更容易实现,并且非熟练者也可以理解。

尽管我同意Java/C#中泛型的整体优点,但我确实错过了特化,接口(interface)灵活性和SFINAE规则。但是,如果我不提及与合理的OO设计有关的一件重要事情,那将是不公平的:如果您对xxx类型的模板特化实际上改变了它的客户端API,那么很可能应该以不同的方式命名它,并形成一个不同的模板。模板可以完成的所有其他操作,大部分都添加到了工具集中,因为...在C++中没有反射,因此必须以某种方式进行仿真。 SFINAE是编译时反射的一种形式。

因此,差异世界中最大的参与者被减少为应用修补程序来掩盖运行时的不足,这几乎是完全缺乏运行时自省(introspection)的一种奇怪的(有益的)副作用:))

因此,我说除了由laguage强制执行的某些任意操作或由运行时平台强制执行的某些任意操作之外,没有其他区别。

它们都是高阶类或函数/方法的一种形式,我认为这是最重要的事情和功能。

关于c# - 是什么使模板与通用模板不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15634970/

相关文章:

c# - 如何使用 HtmlHelper 创建外部超链接?

c# - 正则表达式在空格之间查找一个或多个单词

c# - MeasureString() 为不同的屏幕分辨率提供不同的大小

java - 如何在 Eclipse 中配置/运行 Ant Java 项目

java - android可以将字符串作为代码执行吗?

c++ - 传递给函数时获取包含元素 0 的数组的长度

c# - 算法到 "spread"在 3D 数组上递减值

java - 如何以 Putty 或 Puttygen 可读格式导出 (PKCS#8?) 私钥?

c++ - 通过opencv中的选定像素裁剪图像

c++ - 虚函数不进入基类