c++模板和Java/ c#泛型之间的区别是什么?限制是什么?
What are the Differences between C++ Templates and Java/C# Generics and what are the limits?
我在这里读了一篇有趣的文章/帖子/讨论,我有以下问题:
- Java/c#泛型的限制是什么?
- Java/c#泛型不可能实现的c++模板是什么?
编辑1 Eric Lippert的更多推荐问题
- 有哪些模式可以用c#泛型,但不可能用c++模板? c#的真正泛型类型和Java的类型擦除泛型类型有什么区别?
首先,您可能想要阅读我2009年关于这个主题的文章。
在我看来,c++模板和c#泛型之间的主要区别在于c++模板实际上在构造模板时完全重新编译了代码。c++方法的优缺点有很多:PRO:你可以有效地创建约束,如"类型参数T必须有一个加法运算符";
如果代码中包含一对相互添加的t,那么如果使用不允许添加的类型参数构造模板,则模板将无法编译。CON:您可能会意外创建未记录的约束,如"类型参数T必须有一个加法运算符"。
在c#中,你必须说明哪些约束对用户有帮助,但你仅限于一小部分可能的约束:接口、基类、值与引用类型和默认构造函数约束,仅此而已。
PRO:对于两种不同的结构,语义分析可能完全不同。
CON:对于两种不同的结构,语义分析可能完全不同。如果你不希望这样,这是一个等待发生的错误
在c#中,无论构造多少次类型,语义分析都是一次完成的,因此需要使用任何满足约束的类型参数,而不仅仅是实际提供的类型参数。
PRO:您只生成您需要的结构的代码。
CON:您为使用的所有结构生成代码。
模板可能导致代码段变大。在c#中,泛型类型的IL只生成一次,然后在运行时抖动对程序使用的所有类型进行编码。这有一个小的性能成本,但抖动实际上只为所有引用类型参数生成一次代码,这一事实在一定程度上减轻了性能成本。因此,如果您有List<object>
和List<string>
,那么编译代码只生成一次,并用于两者。List<int>
和List<short>
则相反,两次抛出代码。
PRO:当你使用模板库时,源代码就在那里。
CON:要使用模板库,你必须有源代码。
最后:
PRO: Templates允许模板元编程
CON:模板元编程对于新手来说很难理解。
CON:模板系统实际上不允许一些在泛型系统中非常简单的类型拓扑
例如,我想象在c++中做这样的事情是很困难的:
class D<T>
{
class S { }
D<D<T>.S> ds;
}
在c#泛型中,没有问题。在运行时,对于所有引用类型参数,该类型只构建一次。
但是在c++模板中,当你有D<int>
时会发生什么?内部类型构造了一个D<D<int>.S>
类型的字段,因此我们需要构造该类型。但是该类型构造了一个D<D<D<int>.S>.S>
类型的字段…以此类推,直到无穷
Java/c#泛型的限制是什么?
Java泛型是有限的,因为不可能像c++那样做一些技巧。
为了证明这个说法,这里有一个c++的例子,在Java中单独使用模板是不可能复制的。
基于策略的编程是一种在编译时将(模板化)类的使用限制为继承其他(可能的)模板化类的方法。
编译时泛型和运行时泛型的区别是什么?
交易是编译器知道关于类/模板可能的运行时行为的一切,所以它可以做(目前)c#/Java/任何运行时环境/编译器不可能做的大量优化。
这样做的另一个好处是编译器可以确保模板组合的初始化是有效的,这意味着当程序员想要用无效的组合初始化新对象时,不会发生像Java/c#中那样的运行时错误。
c++泛型有什么缺点?
缺点是模板可能变得非常复杂,难以阅读、理解和调试。这可能是Java开发人员不想在语言中有这样一个野兽的原因之一。
Java/c#泛型不可能实现的c++泛型是什么?
在c++中可以使用其他模板作为模板参数,这在c#/Java中是不可能的,并且允许使用优雅的技巧,如模板元编程。
Java泛型的动机始终是提供类型安全,同时保持向后兼容性。Sun通过添加类型检查,然后在编译过程中擦除泛型类型来实现泛型。代码:
// This applies to JDK 1.5, so I won't use <>.
List<Number> list = new ArrayList<Number>();
list.add(2.0);
list.add(-2);
list.add(new BigDecimal("1.23456789");
等价于
List list = new ArrayList();
Double temp = new Double(2.0); // boxing
if (!temp instanceof Number) throw new ClassCastException();
list.add(temp);
// Similar for -2 and the BigDecimal.
不知道list的类型会使它进入运行时类,但是一些instanceof
可能会被编译器作为安全而删除。
由于编译器不会将泛型类型写入编译后的类文件中,因此在上面的list.getClass() == ArrayList.class
中,不存在像c++中那样的模板特化。List<Boolean>
不能被打包成一个比特序列。所有泛型类型都是类型,不像c++中的模板,比如:
template<int length, int time, int mass>
class measurement {...}
可用于量纲分析,并防止人们在区域中添加长度。
根据MSDN, c#泛型和c++模板之间的主要区别是:
- c#泛型不提供与c++模板相同的灵活性。例如,在c#泛型类中调用算术运算符是不可能的,尽管可以调用用户定义的运算符。 c#不允许非类型模板参数,比如模板C{}。c#不支持显式特化;也就是说,一个特定类型的模板的自定义实现。
- c#不支持部分专门化:对类型参数子集的自定义实现。
- c#不允许将类型参数用作泛型类型的基类。
- c#不允许类型参数有默认类型。
- 在c#中,泛型类型参数本身不能是泛型,尽管构造类型可以用作泛型。c++允许模板参数。
然而,在某些情况下,您可以通过使用扩展方法来解决其中的一些问题。
可用于c++泛型,既不能用于c#泛型也不能用于Java泛型:true 模板元编程(在编译时完成)。
#include <iostream>
template<unsigned U>
struct Fac{ enum { value = U * Fac<U-1>::value};};
template<>
struct Fac<0>{ enum { value = 1};};
template<unsigned U>
struct Fib{ enum {value = (Fib<U-1>::value + Fib<U-2>::value)};};
template<>
struct Fib<0>{ enum {value = 0};};
template<>
struct Fib<1>{ enum {value = 1};};
template<unsigned U>
void show(){
show<U-1>();
std::cout << "Fib(" << U << ")=" << Fib<U>::value << "t" << "Fac(" << U << ")=" << Fac<U>::value << std::endl;
}
template<>
void show<0>(){}
int main(int argc, char** argv){
show<12>();
}
http://ideone.com/Gdf3W 编辑
c++标准没有对类型参数的约束,而c#和Java有。Boost也有类似的功能(Boost Concept Check Library)。但是从c++ 11开始,你现在可以使用<type_traits>
来获得类似的东西。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- C++避免重复声明的语法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 这些情况有什么区别?我怎么知道什么是临时对象?
- 如果我提前将参数声明为变量而不是将它们内联写入函数调用,那有什么区别(在内存方面)?
- C++和Python之间平等含义的区别的根源是什么?
- 尾随空格是什么意思,它和空白有什么区别?
- 调试构建和发布构建、区别和用途是什么意思
- std::ifstream::in 和 std::ios::in 有什么区别?(显然是 C++ 中 std::ifstr
- 在 C++ STL 的比较函数中使用"<="符号而不是"<"符号有什么区别?
- 在头中声明变量而不是在源文件(cpp/h)中声明变量有什么区别
- "Thing thing;"和"Thing thing = Thing();"有什么区别,什么时候应该使用一个而不是另一个?
- 如果 a 是 cv::Mat 和 cv::Mat b=a.row(1),那么两个 cv::Mat 实例有什么区别
- 如果f是双精度数,f+=1和f+=1.0有什么区别吗?
- char和CString的区别和关系是什么?
- 那么,是什么区别了template(c.end(),_1)和template_back(_1)呢
- C++:按变量值而不是数字移位 ->有什么区别?