使用通配符将Java泛型编译为C ++模板 [英] Compiling Java Generics with Wildcards to C++ Templates

查看:127
本文介绍了使用通配符将Java泛型编译为C ++模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图构建一个Java到C ++的转换编译器(即Java代码进来,语义上等同(或多或少)C ++代码出来)。

I am trying to build a Java to C++ trans-compiler (i.e. Java code goes in, semantically "equivalent" (more or less) C++ code comes out).

不考虑垃圾收集,语言是相当熟悉的,所以整个过程工作已经很好。然而,一个问题是在C ++中不存在的泛型。当然,最简单的方法是用Java编译器执行擦除。然而,生成的C ++代码应该是很好的处理,所以如果我不会失去通用类型信息,这将是很好的,即,如果C ++代码仍然工作与 List< X> ; 而不是 List 。否则,C ++代码将需要在使用此类泛型的任何地方进行显式转换。这是容易出错和不方便的。

Not considering garbage collection, the languages are quite familiar, so the overall process works quite well already. One issue, however, are generics which do not exist in C++. Of course, the easiest way would be to perform erasure as done by the java compiler. However, the resulting C++ code should be nice to handle, so it would be good if I would not lose generic type information, i.e., it would be good, if the C++ code would still work with List<X> instead of List. Otherwise, the C++ code would need explicit casting everywhere where such generics are used. This is bug-prone and inconvenient.

所以,我试图找到一种方法,以某种方式获得一个更好的代表的泛型。当然,模板似乎是一个很好的候选人。虽然他们是完全不同的(元编程vs.编译期只有类型增强),它们仍然可以是有用的。只要没有使用通配符,只需将通用类编译为模板即可。

So, I am trying to find a way to somehow get a better representation for generics. Of course, templates seem to be a good candidate. Although they are something completely different (metaprogramming vs. compile-time only type enhancement), they could still be useful. As long as no wildcards are used, just compiling a generic class to a template works reasonably well. However, as soon as wildcards come into play, things get really messy.

例如,考虑以下列表的java构造函数:

For example, consider the following java constructor of a list:

class List<T>{
List(Collection<? extends T> c){
    this.addAll(c);
}
}

//Usage
Collection<String> c = ...; 
List<Object> l = new List<Object>(c);

如何编译这个?我有使用链锯重新解释模板之间转换的想法。然后,上面的示例可以编译成如下:

how to compile this? I had the idea of using chainsaw reinterpret cast between templates. Then, the upper example could be compiled like that:

template<class T>
class List{
List(Collection<T*> c){
    this.addAll(c);
}
}

//Usage
Collection<String*> c = ...; 
List<Object*> l = new List<Object*>(reinterpret_cast<Collection<Object*>>(c));

然而,问题是这个重新解释转换是否产生预期的行为。当然,它是脏的。但它会工作吗?通常, List< Object *> List< String *> 应具有相同的内存布局,模板参数只是一个指针。但是这是保证吗?

however, the question is whether this reinterpret cast produces the expected behaviour. Of course, it is dirty. But will it work? Usually, List<Object*> and List<String*> should have the same memory layout, as their template parameter is only a pointer. But is this guaranteed?

我想到的另一个解决方案是使用通配符替换方法,通过模板方法来实现每个通配符参数,即编译构造函数到

Another solution I thought of would be replacing methods using wildcards by template methods which instanciate each wildcard parameter, i.e., compile the constructor to

template<class T>
class List{

template<class S>
List(Collection<S*> c){
    this.addAll(c);
}
}

当然,所有其他涉及通配符的方法, code> addAll 将需要模板参数。这种方法的另一个问题是例如在类字段中处理通配符。我不能在这里使用模板。

of course, all other methods involving wildcards, like addAll would then also need template parameters. Another problem with this approach would be handling wildcards in class fields for example. I cannot use templates here.

第三种方法是混合的:一个泛型类被编译为模板类(调用 T < X> )和已擦除的类(称为 E )。模板类 T 从已删除的类 E 继承,因此总是可以通过向上转换E.然后,所有包含通配符的方法将使用已擦除的类型进行编译,而其他方法可以保留完整的模板类型。

A third approach would be a hybrid one: A generic class is compiled to a template class (call it T<X>) and an erased class (call it E). The template class T<X> inherits from the erased class E so it is always possible to drop genericity by upcasting to E. Then, all methods containing wildcards would be compiled using the erased type while others could retain the full template type.

你对这些方法有什么看法?你在哪里看到他们的缺点?
你有什么其他想法如何通配符可以实现尽可能干净,尽可能多的通用信息在代码尽可能?

What do you think about these methods? Where do you see the dis-/advantages of them? Do you have any other thoughts of how wildcards could be implemented as clean as possible while keeping as much generic information in the code as possible?

推荐答案

如果目标是在C ++中表示Java语义,那么最直接的方式。不要使用 reinterpret_cast ,因为它的目的是击败 C ++的本地语义。 (在高级类型之间这样做几乎总是导致一个程序被允许崩溃。)

If the goal is to represent Java semantics in C++, then do so in the most direct way. Do not use reinterpret_cast as its purpose is to defeat the native semantics of C++. (And doing so between high-level types almost always results in a program that is allowed to crash.)

您应该使用引用计数,或类似的机制一个自定义的垃圾收集器(虽然听起来不可能在这种情况下)。

You should be using reference counting, or a similar mechanism such as a custom garbage collector (although that sounds unlikely under the circumstances). So these objects will all go to the heap anyway.

将通用的 List 对象放在堆上,并使用一个单独的类作为 List< String> 或任何其他访问。这样,持久化对象具有通用类型,可以处理任何不正确的访问它的方式,Java可以表达。访问器类只包含一个指针,它已经用于引用计数(即它将本地引用,而不是堆的对象),并暴露适当的向下转换的接口。您甚至可以使用泛型源代码生成访问器的模板。如果你真的想尝试。

Put the generic List object on the heap, and use a separate class to access that as a List<String> or whatever. This way, the persistent object has the generic type that can handle any ill-formed means of accessing it that Java can express. The accessor class contains just a pointer, which you already have for reference counting (i.e. it subclasses the "native" reference, not an Object for the heap), and exposes the appropriately downcasted interface. You might even be able to generate the template for the accessor using the generics source code. If you really want to try.

这篇关于使用通配符将Java泛型编译为C ++模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆