C ++模板和Java / C#generics之间有什么区别?有什么限制?
我从这里读了一篇有趣的文章/主题/讨论,我得到了以下问题:
- Java / C#generics有哪些局限性?
- 使用Java / C#generics不可能使用C ++模板有什么可能?
编辑1 Eric Lippert提出的更多推荐问题
- 使用C#generics可以实现哪些模式但使用C ++模板却无法实现?
- C#的真正generics类型和Java的类型擦除generics类型有什么区别?
首先,您可能想阅读我关于这个主题的2009年文章 。
我认为C ++模板和C#generics之间的主要区别在于C ++模板实际上在构造模板时完全重新编译代码 。 C ++方法的优点和缺点很多:
-
PRO:您可以有效地创建约束,例如“类型参数T必须具有加法运算符”; 如果代码包含几个相互添加的Ts,那么如果使用不允许添加的类型参数构造模板,则模板将无法编译。
-
CON:您可能会意外地创建未记录的约束,例如“类型参数T必须具有加法运算符”。
在C#中,你必须说出哪些约束对用户有帮助,但是你只能受限于一小部分可能的约束:接口,基类,值与引用类型和默认构造函数约束,这就是全部。
-
PRO:对于两种不同的结构,语义分析可能完全不同。 如果你想要那个,那就太棒了。
-
CON:对于两种不同的结构,语义分析可以完全不同。 如果你不想那样,这就是等待发生的错误。
在C#中,语义分析无论构造类型多少次都会完成一次 ,因此需要使用满足约束的任何类型参数,而不仅仅是实际提供的类型参数。
-
PRO:您只生成所需构造的代码。
-
CON:您为所使用的所有构造生成代码。
模板可能导致codegen变大。 在C#中,生成generics类型的IL一次,然后在运行时,抖动会为程序使用的所有类型执行codegen。 这具有较小的性能成本,但由于抖动实际上仅为所有引用类型参数生成一次代码,因此可以稍微减轻它。 因此,如果您有List
和List
则jitted代码仅生成一次并用于两者。 List
和List
相比之下两次代码。
-
PRO:当您使用模板库时,您就拥有源代码。
-
CON:要使用模板库,您必须拥有源代码。
在C#中,generics类型是一流类型。 如果将它们粘贴在库中,则可以在任何地方使用该库,而无需提供源代码。
最后:
-
PRO:模板允许模板元编程。
-
CON:新手很难理解模板元编程。
-
CON:模板系统实际上不允许在通用系统中非常简单的某些类型拓扑。
例如,我想在C ++中很难做到这样的事情:
class D { class S { } D.S> ds; }
在C#generics中,没问题。 在运行时,类型仅为所有引用类型参数构建一次 。
但是在C ++模板中,当你有D
时会发生什么? 内部类型构造一个D
类型的字段,因此我们需要构造该类型。 但是那种类型构造了一个类型为D
……的字段,依此类推到无穷大。
Java / C#generics有哪些局限性?
Javagenerics是有限的,因为不可能像C ++那样做一些技巧。
为了certificate这里的主张是一个C ++示例,在Java中单独使用模板是不可能的。
基于策略的编程是一种在编译时限制(模板化)类对inheritance的其他(可能的)模板化类的使用的方法。
编译时generics与运行时generics有什么关系?
交易是编译器知道关于类/模板的可能的运行时行为的一切,因此它可以使用C#/ Java /任何运行时环境/编译器进行(当前)不可能的大量优化。
另一个好的方面是编译器可以确保模板组合的实例化是有效的,这意味着当程序员想要用新的对象实现新的对象时,不可能像Java / C#那样发生运行时错误。一个无效的组合。
C ++generics的缺点是什么?
缺点是模板的读取,理解和调试都非常复杂。 这可能是Java开发人员不希望在语言中拥有这样一个野兽的原因之一。
使用Java / C#generics不可能使用C ++ Generics有什么可能?
在C ++中可以使用其他模板作为模板参数,这在C#/ Java中是不可能的,并且允许像模板元编程这样的优雅技巧。
Java Generics的动机始终是提供类型安全性,同时保持向后兼容性。 Sun通过添加类型检查然后在编译过程中删除generics类型来实现generics。 代码如:
// This applies to JDK 1.5, so I won't use <>. List list = new ArrayList (); 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.
不知道列表的类型使其成为运行时类,但编译器可能会删除某些instanceof
,因为它们是安全的。
由于编译器不会将generics类型写入已编译的类文件中,因此上面的list.getClass() == ArrayList.class
,因此不能像C ++中那样使用模板特化。 List
无法打包成一系列位。 所有generics类型都是类型,与C ++中的模板不同,如:
template class measurement {...}
它可以用于尺寸分析,并防止人们增加区域长度。
根据MSDN ,C#generics和C ++模板之间的主要区别是:
- C#generics不提供与C ++模板相同的灵活性。 例如,虽然可以调用用户定义的运算符,但不可能在C#generics类中调用算术运算符。
- C#不允许非类型模板参数,例如模板C {}。
- C#不支持显式专业化; 也就是说,特定类型的模板的自定义实现。
- C#不支持部分特化:类型参数子集的自定义实现。
- C#不允许将type参数用作generics类型的基类。
- C#不允许类型参数具有默认类型。
- 在C#中,generics类型参数本身不能是通用的,尽管构造的类型可以用作generics。 C ++确实允许模板参数。
但是,在某些情况下,您可以使用扩展方法解决其中一些问题。
C ++generics可能,C#generics也不是Javagenerics:真正的模板元编程 (在编译时图灵完成)。
#include template struct Fac{ enum { value = U * Fac::value};}; template<> struct Fac<0>{ enum { value = 1};}; template struct Fib{ enum {value = (Fib::value + Fib::value)};}; template<> struct Fib<0>{ enum {value = 0};}; template<> struct Fib<1>{ enum {value = 1};}; template void show(){ show(); std::cout << "Fib(" << U << ")=" << Fib::value << "\t" << "Fac(" << U << ")=" << Fac::value << std::endl; } template<> void show<0>(){} int main(int argc, char** argv){ show<12>(); }
编辑
当C#和Java有C ++标准时,C ++标准没有对类型参数的约束。 Boost有类似的东西( Boost Concept Check Library )。 但是从C ++ 11开始,你现在可以使用
来获得类似的东西。
- Asp.net Button组件在Twitter-Bootstrap主题下不起作用
- 数据网格视图和tabcontrol C#的奇怪问题
- 从Javascript将KeyValuePair或IDictionary的列表传递给Web Api控制器
- 我正在尝试编组从C到C#的结构,不知道从哪里开始
- 派生和基类,我可以明确设置基数吗?
- BitBlt屏幕截图无法在Windows 10上运行
- C#:如何在文本框中按下输入触发按钮,但仍允许“Ctrl + A”等快捷方式通过?
- C#Selenium webdriver JavaScript错误记录
- 使用ASP.Net MVC 4 Web API和Ninject.Web.WebApi发布问题