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 whencfg!
is used for the condition, regardless of whatcfg!
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();
}};
}