重复
大家好,
我是一名经验丰富的C++程序员,但对C#还比较新。
那些约束和泛型是怎么回事?为什么它不像在C++中一样,约束是隐式的,并从您对模板类进行的实例化中派生出来的呢?
为什么微软没有使其与C++中的工作方式相同呢?
大家好,
我是一名经验丰富的C++程序员,但对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
是可复制的,因为该使用出现在接口中,而不是模板主体中。其他要求是使用要求子句陈述的。现在,如果用户使用没有定义op+
的类型,用户将获得适当的错误消息。template<typename T> requires MyCuteType<T>
void f(T t) { *t = 10; }
然后,使用一个 int
调用 f
函数!只需为 MyCuteType<int>
编写一个概念映射,教会编译器如何对 int 进行解引用即可。这在像下面这样的循环中非常方便:
for_each(0, 100, doSomething());
C++0x概念未被接受进入草案,但已在2009年末被投票淘汰。太遗憾了!但也许我们会在下一个C++版本中再次看到它?让我们都抱有希望!
template <typename T, unsigned int dim>
class math_vector
{
T elements[dim];
math_vector<T,dim> operator+ (const math_vector<T,dim>& other) const
{
math_vector<T,dim> result;
for (unsigned int i = 0; i < dim; ++i)
result.elements[i] = elements[i] + other.elements[i];
}
}
struct employee
{
char name[100];
int age;
float salary;
}
math_vector<int, 3> int_vec; //legal
math_vector<float, 5> float_vec; //legal
math_vector<employee, 10> employee_vec; //illegal, operator+ not defined for employee
operator+
并将其用作math_vector
的参数。因此,仅当类型满足模板代码定义的约束条件时,模板参数才有效。这很灵活,但会导致编译时间长(每次实例化模板时都必须检查类型是否满足模板的约束条件)。
C#泛型:与其检查每个特定实例的有效性(导致编译时间更长且容易出错),您明确声明泛型参数必须实现特定接口(一组方法、属性和运算符)。在泛型代码内部,您无法自由调用任何方法,而只能调用该接口支持的方法。每次实例化泛型时,运行时不必检查参数是否满足一长串约束条件,而只需检查它是否实现了指定的接口。当然,这样做的灵活性较小,但出错的可能性也较小。例如:class SortedList<T> where T : IComparable<T>
{
void Add(T i) { /* ... */ }
}
class A : IComparable<A> { /* ... */ }
class B
{
int CompareTo(B b) { /* ... */ }
bool Equals(B b) { /* ... */ }
}
SortedList<A> sortedA; // legal
SortedList<B> sortedB; // illegal
// B implements the methods and properties defined in IComparable,
// however, B doesn't explicitly implement IComparable<B>
C# 泛型与 C++ 完全不同。
在 C# 中,编译器基本上为所有对象类型编译一个类定义,并为每个值类型编译一个类定义。
而在 C++ 中,每种类型都有自己的类定义。
约束只是为了让编译器从其他位置推断出一些信息。
我建议看一下 Action<T>
、Func<T, T>
和 Predicate<T>
委托以及相关的 IEnumerable
扩展方法。使用 lambda 函数并结合这些委托,你就能看到约束所起的作用。
模板和泛型确实是两个不同的概念。
泛型的一个目标是能够以跨库、跨语言的方式使用它们,这与 C++ 模板不同。它们是 CLR 的概念,而不是语言概念(尽管它们显然需要语言支持)。
在 C++ 中,模板可以被看作是“超级宏”,因为你可以将它们视为文本扩展,然后进行编译。这使得它们能够使用模板参数中定义的任何内容(主要是运算符),因为约束是由使用它们的代码所强制的。
在 .NET 中,由于泛型是在运行时解析(实例化)的,所以必须在定义级别上施加约束,以便编译器可以确保它们的使用是有效的(这意味着您不能在泛型参数上使用运算符,因为您无法指示存在运算符的约束)。
正如我所说,泛型的主要目的是能够创建通用的 DLL 供其他项目使用。这就是它们与其他概念的不同之处。