0

我知道在 C++ 中,泛型实际上并不存在,但您可以使用template. 当您构建代码时,编译器会预处理代码并生成一个新代码,其中将泛型值替换为对象声明中指定的实际值,然后才是真正编译的新代码。例如,假设我们有A如下类:

template<class T>
class A
{
    T f();
};

然后在我们拥有的代码中的其他地方A<int> a;。编译的实际代码是:

class A
{
    //Replaces T by int in the pre-processing
    int f();
};

在整个介绍之后,让我们进入正题。

我的问题是:

  • C# 对待泛型的方式与 C++ 相同吗?如果没有,那怎么办?
  • 它们是特殊类型吗?
  • 它们是在运行时还是在编译时解决的?
  • 激活寄存器中为泛型类型保留了多少空间?
4

3 回答 3

6

这是一个非常广泛的主题,可以通过以下方式更好地解释:

http://msdn.microsoft.com/en-us/library/c6cyy67b.aspx

总结(来自上面链接的 MSDN 文章):

  • C# 泛型不提供与 C++ 模板相同的灵活性。例如,不能在 C# 泛型类中调用算术运算符,但可以调用用户定义的运算符。

  • C# 不允许非类型模板参数,例如模板 C {}。

  • C# 不支持显式特化;也就是说,特定类型的模板的自定义实现。

  • C# 不支持部分特化:类型参数子集的自定义实现。

  • C# 不允许将类型参数用作泛型类型的基类。

  • C# 不允许类型参数具有默认类型。

  • 在 C# 中,泛型类型参数本身不能是泛型,尽管构造类型可以用作泛型。C++ 确实允许模板参数。

  • C++ 允许代码可能对模板中的所有类型参数都无效,然后检查用作类型参数的特定类型。C# 要求类中的代码以这样一种方式编写,即它可以与任何满足约束的类型一起使用。例如,在 C++ 中,可以编写一个对类型参数的对象使用算术运算符 + 和 - 的函数,这将在使用不支持这些运算符的类型实例化模板时产生错误。C# 不允许这样做;唯一允许的语言结构是那些可以从约束中推导出来的结构。

一般来说,尽管它们在大多数情况下共享相似的语法和用途,但在用法和功能上存在许多很大的差异。

于 2013-03-22T05:22:13.813 回答
3

关于如何解析 C++ 模板存在误解。在 C++ 中,模板会被处理两次(注意:“预处理”一词是为预处理器保留的,与模板完全无关)。

在第一次处理时,非依赖名称被解析,而依赖名称未被解析:

int x;

template <typename T> foo() {
    x;    // <-- resolved in phase 1
    T::x; // resolved in phase 2, depends on "T"
}

实例化时进入阶段 2。例如:

struct Frob {
    int x;
};

int main () {
    foo<Frob>();
} // <-- instantiation happens right before the '}'

此外,C++ 模板是在每个函数的基础上延迟实例化的。这意味着并非类模板中的所有内容都必须是可解析的。仅实例化实际使用的函数,这意味着仅对已使用的成员函数进入阶段 2。

这使得模板比 C# 风格的泛型更通用:当你实例化一个类模板时,实例化的类型只需要支持模板的一个子集。

在 C# 中,泛型被急切地解决了。“实例化”类型必须支持泛型类仅可能使用的所有内容,这对多功能性提出了相当严格的限制。

你已经知道了,但两者都是截然不同的概念。泛型是一种运行时构造,并且具有反射和自修改代码,C# 语言必须具有很强的可解析性。模板是一种编译时构造(注意:不是 _preprocessing 构造!),支持具有类型和非类型参数的图灵完备的元编程,以及在急切和惰性实例化之间的强大折衷。

两者都有自己的特点。

于 2013-03-22T05:30:12.357 回答
1

.NET 泛型的实现是一种混合。

当泛型类被编译成 MSIL 时,它被编译成单个泛型类型定义。

当客户端使用泛型类时,.NET 运行时为简单类型参数(bool、int 等)编译类的机器代码的单独副本,但不会为不同的对象类型生成单独的代码;他们都共享对象的代码。

于 2013-03-22T05:23:06.143 回答