I’d like to provoke some discussion about what can be done for better interoperability between Rust and C++, especially when templates are involved. I think everybody around here is going to agree that easy Rust/C++ interop would be a boon for Rust adoption among the current C++ users.
State of the art
To recap, I know of three projects that currently offer some level of C++ interop:
- rust-bindgen can generate Rust FFI declarations for C functions and structures based on a C header. No direct C++ support, however one can manually create C wrappers around C++ API.
- rust-bindgen/sm-hacks adds some support for C++ classes.
- rust-cpp allows to insert C++ statements inline in the Rust code.
[In my reckoning, the latter is the more promising approach, since it does not involve trying to express in Rust some of the C++ features that do not have direct Rust equivalents (constructors, overloading, inheritance, etc). The opposite, i.e. expressing Rust constructs in C++, seems much easier.]
Sadly, none of the above allow using C++ templates directly.
Well, what can be done? The ideas I’ve seen to date fall roughly in two categories:
Early (explicit) specialization
The idea here is to require developer to specify all template specializations upfront. The code generator can then create wrappers for all of the requested specializations.
Optionally, such instantiations can be bound together, via a common trait (in a manner similar to this), so that at the Rust level users would see a semblance of a generic type, rather than N distinct types.
The downside is, of course, that the set of specializations is closed. If author of the Rust crate wrapping that C++ library had neglected to provide a specialization for your favorite type, well, tough luck…
Late template specialization
The other end of the spectrum is to delay wrapper generation until after type inference and codegen, so that we’d know exactly what needs to be instantiated:
- Allow foreign functions to be generic.
- Monomorphize FFI fn’s by generating a new extern symbol for each type parameter combination encountered.
- After all Rust codegen is done, generate C wrappers for each FFI monomorphization encountered in step 2.
The biggest issue with this seems to be the “infectiousness” of generic FFI: if a generic function, that internally depends on a generic FFI API is exported from the current crate, downstream crates will be able to cause new monomorphizations of the FFI stub to be created, and thus will become dependent on the codegen plugin, the C++ compiler, as well as the C++ library all being around to generate code for the new monomorphizations.
How many people would consider early specialization sufficient for most purposes, and how many think that we need to go the whole way?