Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust static variables as C++ non-type template parameter #80

Open
ffranr opened this issue May 24, 2020 · 4 comments
Open

Rust static variables as C++ non-type template parameter #80

ffranr opened this issue May 24, 2020 · 4 comments

Comments

@ffranr
Copy link

ffranr commented May 24, 2020

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.

@dtolnay
Copy link

dtolnay commented May 24, 2020

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() {}
      |      ^~~

@ffranr
Copy link
Author

ffranr commented May 24, 2020

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?

@ogoffart
Copy link
Collaborator

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.

@ffranr
Copy link
Author

ffranr commented May 26, 2020

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants