简体   繁体   中英

Different versions of the same function with conditional compilation in Rust

I'm trying to create two different versions of the same function, only one of which will be compiled. As an example:

#[cfg(debug_assertions)]
fn do_something(x: usize) -> usize {
    x + 1
}

#[cfg(not(debug_assertions))]
fn do_something() -> usize {
    0
}

This works fine and I can also call the correct version of do_something if I know which one I'm calling (In practice, the functions will do the exact same thing, the debug one just requires more info for some validation). So I can create two corresponding main functions:

#[cfg(debug_assertions)]
fn main() {
    do_something(0);
}

#[cfg(not(debug_assertions))]
fn main() {
    do_something();
}

But this is very clumsy, and I want to have only one version of the code that doesn't depend on debug_assertions . I'd like to do something like:

macro_rules! call {
    ($func:ident, $optional_arg:expr) => {{
        if cfg!(debug_assertions) {
            $func($optional_arg);
        } else {
            $func();
        }
    }};
}

fn main() {
    call!(do_something, 0);
}

and then re-use the macro wherever I call this function, or similar ones. But this doesn't compile:

  --> main.rs:16:13
   |
2  | fn do_something(x: usize) -> usize {
   | ---------------------------------- defined here
...
16 |             $func();
   |             ^^^^^-- supplied 0 arguments

   |             |
   |             expected 1 argument
...
22 |     call!(do_something, 0);
   |     ----------------------- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

I don't understand why I get the error, since the wrong function call shouldn't even be compiled. The error can be fixed by forcing the functions to have the same signature and simply ignoring the unnecessary argument in the release version, but that doesn't seem like the right way to go.

What would you do in this situation? Why doesn't the macro example compile?

From the reference :

cfg! , unlike #[cfg] , does not remove any code and only evaluates to true or false. For example, all blocks in an if/else expression need to be valid when cfg! is used for the condition, regardless of what cfg! is evaluating

Flags will be evaluated in compile time but you are doing this check at runtime. You need to use attributes to avoid the problem:

macro_rules! call {
    ($func:ident, $optional_arg:expr) => {{
        #[cfg(debug_assertions)]
        $func($optional_arg);

        #[cfg(not(debug_assertions))]
        $func();
    }};
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM