Rust static variables as C++ non-type template parameter
ffranr opened this issue · 4 comments
Hello!
I'm trying to use a Rust static variable as a C++ non-type template parameter. Is this possible?
This is a simple example which outlines what I'm trying to do:
#[macro_use]
extern crate cpp;
cpp! {{
#include <iostream>
#include "src/tmp.h"
}}
static NUMBER: i32 = 42;
fn foo() {
unsafe {
cpp!([NUMBER as "int32_t"] {
const int32_t replace_me_with_number = 3;
std::cout << Add<replace_me_with_number>() << " " << NUMBER << std::endl;
})
};
}
#[cfg(test)]
mod tests {
use crate::foo;
#[test]
fn it_works() {
foo();
}
}
I'm trying to replace replace_me_with_number
with NUMBER
.
src/tmp.h
is just:
template <int32_t N>
int Add()
{
return N + 3;
}
Thank you for your help.
This isn't valid C++ code. The same thing wouldn't compile in plain C++ either.
#include <cstdint>
template <int32_t N>
void Add() {}
static int32_t NUMBER = 42;
int main() {
Add<NUMBER>();
}
$ clang++ main.cc
main.cc:9:3: error: no matching function for call to 'Add'
Add<NUMBER>();
^~~~~~~~~~~
main.cc:4:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'N'
void Add() {}
^
$ g++ main.cc
main.cc: In function ‘int main()’:
main.cc:9:7: error: the value of ‘NUMBER’ is not usable in a constant expression
9 | Add<NUMBER>();
| ^~~~~~
main.cc:6:16: note: ‘int32_t NUMBER’ is not const
6 | static int32_t NUMBER = 42;
| ^~~~~~
main.cc:9:15: error: no matching function for call to ‘Add<NUMBER>()’
9 | Add<NUMBER>();
| ^
main.cc:4:6: note: candidate: ‘template<int N> void Add()’
4 | void Add() {}
| ^~~
Thank you for the reply @dtolnay (btw, I love your work!)
I agree with you that the example C++ snippet that you have provided is not valid C++. However, I'm not trying to produce that sort of code. This is the sort of valid C++ that I hope to produce:
#include <cstdint>
template <int32_t N>
void Add() {}
static const int32_t NUMBER = 42;
int main() {
Add<NUMBER>();
}
How can I pass a Rust variable (whose value is known at compile time) to the C++ side such that it can be used as a non-type template parameter?
What is the real use case you have in mind for this feature?
The C++ compilation is done before the rust compilation, and as such the C++ do not have access to anything that the rust compiler sees.
Now, we could make them available to cpp_build.
For example, we could imagine an annotation such as:
#[cpp::export_static(as "uint32_t")]
static NUMBER: u32 = 42;
Which would tell cpp_build to generate constexpr uint32_t NUMBER = 42;
This would have the following drawback:
- The cpp_build parser is not a full rust parser, and matching the
#[cpp::export_static]
might not work in 100% of the cases. - The right hand side of the
=
must also be a very simple expression that cpp_build can understand, so basically that would be limited to plain constant numbers.
Thanks for the reply @ogoffart.
I think you're right that I need to take a step back and make sure my strategy makes sense. My ultimate goal is to build a Rust library which wraps the SDSL C++ library.
SDSL provides data structures such as the int_vector
, where the elements of the vector have a predetermined set bit width:
template<uint8_t t_width>
class int_vector
There are other data structures which are a more complicated. Their templates are parameterized on types. For example the wavelet tree class for integer sequences:
template<class t_bitvector = bit_vector,
class t_rank = typename t_bitvector::rank_1_type,
class t_select = typename t_bitvector::select_1_type,
class t_select_zero = typename t_bitvector::select_0_type>
class wt_int
I think that what you've suggested above (#[cpp::export_static(as "uint32_t")]
) might solve the most basic cases. And the drawbacks that you've suggested would be acceptable.
How do you think I should go about writing a wrapper for this library?