What are the Differences between C++ Templates and Java/C# Generics and what are the limits? [closed]

▼魔方 西西 提交于 2019-12-18 13:27:56

问题


I read an interesting Article/Thread/Discussion from here and i got following questions:

  • What are the limitations of Java/C# generics?
  • What is possible with C++ Templates that is impossible with Java/C# generics?

Edit 1 More recommended questions by Eric Lippert

  • What are some patterns that are possible with C# generics but impossible with C++ templates?
  • What's the difference between C#'s true generic types and Java's type erasure generic types?

回答1:


First off, you might want to read my 2009 article on this subject.

The primary difference to my mind between C++ templates and C# generics is that C++ templates actually completely recompile the code upon construction of the template. The pros and cons of the C++ approach are many:

  • PRO: You can effectively create constraints like "the type argument T must have an addition operator"; if the code contains a couple of Ts added to each other then the template will not compile if you construct it with a type argument that doesn't permit addition.

  • CON: You can accidentally create undocumented constraints like "the type argument T must have an addition operator".

In C# you have to say what the constraints are which helps the user, but you are limited to only a small set of possible constraints: interfaces, base classes, value vs reference type and default constructor constraints, and that's all.

  • PRO: Semantic analysis can be completely different for two different constructions. If you want that, that's awesome.

  • CON: Semantic analysis can be completely different for two different constructions. If you don't want that, that's a bug waiting to happen.

In C# the semantic analysis is done once no matter how many times the type is constructed, and it is therefore required to work with any type argument that meets the constraints, not just the type arguments that are actually supplied.

  • PRO: You only generate the code for exactly the constructions you need.

  • CON: You generate the code for all the constructions you use.

Templates can cause codegen to get large. In C#, the IL for a generic type is generated once, and then at runtime the jitter does codegen for all the types your program uses. This has a small performance cost, but it is mitigated somewhat by the fact that the jitter actually only generates code once for all reference type arguments. So if you have List<object> and List<string> then the jitted code is only generated once and used for both. List<int> and List<short> by contrast jits the code twice.

  • PRO: when you use a template library, you have the source code right there.

  • CON: to use a template library you have to have the source code.

In C#, generic types are first-class types. If you stick them in a library, you can use that library anywhere without having to ship the source code.

And finally:

  • PRO: Templates permit template metaprogramming.

  • CON: Template metaprogramming is hard to understand for novices.

  • CON: The template system actually does not permit some type topologies that are extremely straightforward in a generic system.

For example, I imagine that it would be difficult to do something like this in C++:

class D<T> 
{
    class S { }
    D<D<T>.S> ds;
}

In C# generics, no problem. At runtime the type is only built once for all reference type arguments.

But in C++ templates, what happens when you have D<int>? The interior type constructs a field of type D<D<int>.S>, so we need to construct that type. But that type constructs a field of type D<D<D<int>.S>.S>... and so on to infinity.




回答2:


What are the limitations of Java/C# generics?

Java generics are limited because it is not possible to do some tricks like in C++.

To proof the claim here is an C++ example that is impossible to reproduce with templates alone in Java.

Policy based programming is a way to restrict the use of an (templated) class to other (possible) templated classes on inheritence at compile time.

What is the big deal of compile time generics vs runtime generics?

The deal is that the compiler knows everything about the possible runtime behaviour of the class/templates so it can do heavy optimizations that are (currently) impossible with an C#/Java/whatever runtime environment/compiler.

A other good side of this is that the compiler can ensure that the instatiation of a combination of the templates is valid which means that there is no possibility that runtime-errors can happen like in Java/C# when the programmer want to instatiate new objects with an invalid combination.

What is the downside of C++ generics?

The downside is that the templates can get really complicated to read and understand and debug. This is (maybe) one of the reasons why the Java developers didn't want to have such a beast in a language.


What is possible with C++ Generics that is impossible with Java/C# generics?

In C++ is is possible to use other templates as template parameters which is impossible in C#/Java and which allows elegant tricks like template-metaprogramming.




回答3:


The motivation for Java Generics was always to provide type safety, while keeping backwards compatibility. Sun implemented generics by adding type checks and then erasing the generic type as part of compilation. Code like:

// 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");

is equivalent to

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.

No knowledge of the type of list makes it into the runtime classes, but some of the instanceofs may be dropped by the compiler as being safe.

Since the compiler does not write the generic types into the compiled class files, and so the above list.getClass() == ArrayList.class, there can be no template specializations as in C++. List<Boolean> cannot be packed into a sequence of bits. All generic types are types, unlike templates in C++ like:

template<int length, int time, int mass>
class measurement {...}

which can be used for dimensional analysis, and to keep people from adding lengths to areas.




回答4:


According to MSDN the key differences between C# generics and C++ templates are:

  • C# generics do not provide the same amount of flexibility as C++ templates. For example, it is not possible to call arithmetic operators in a C# generic class, although it is possible to call user defined operators.
  • C# does not allow non-type template parameters, such as template C {}.
  • C# does not support explicit specialization; that is, a custom implementation of a template for a specific type.
  • C# does not support partial specialization: a custom implementation for a subset of the type arguments.
  • C# does not allow the type parameter to be used as the base class for the generic type.
  • C# does not allow type parameters to have default types.
  • In C#, a generic type parameter cannot itself be a generic, although constructed types can be used as generics. C++ does allow template parameters.

Yet there are cases where you can work around some of these issues by using extension methods.

Possible with C++ generics, neither with C# generics nor Java generics: true template metaprogramming (turing complete at compile time).

#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

Edit

The C++ standard hadn't had constraints on type parameters while C# and Java have. Boost has something like that (Boost Concept Check Library). But since C++11 you now can use <type_traits> to get something similar.



来源:https://stackoverflow.com/questions/15857544/what-are-the-differences-between-c-templates-and-java-c-generics-and-what-are

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!