Constexpr equivalent

Hi. I want to mimic the constexpr function in C++. The code below shall be straightforward and needs little explanation.

const UNIT_TUPLE: [(u64, &str); 6] = (|| -> [(u64, &'static str); 6]{
  let i = 1_u32;
  [
    (1024_u64.checked_pow(i.add_one()).unwrap(), "KiB"),
    (1024_u64.checked_pow(i.add_one()).unwrap(), "MiB"),
    (1024_u64.checked_pow(i.add_one()).unwrap(), "GiB"),
    (1024_u64.checked_pow(i.add_one()).unwrap(), "TiB"),
    (1024_u64.checked_pow(i.add_one()).unwrap(), "PiB"),
    (1024_u64.checked_pow(i.add_one()).unwrap(), "EiB")
  ]
})();

This variable is completely "generate-able" at compile-time, and I believe its C++ version works without any problem using constexpr keyword.

Any clue to achieve this in Rust? Thanks!

const UNIT_TUPLE: [(u64, &str); 6] = {
    let mut i = 0;
    [
        (1 << (10 * { i += 1; i }), "KiB"),
        (1 << (10 * { i += 1; i }), "MiB"),
        (1 << (10 * { i += 1; i }), "GiB"),
        (1 << (10 * { i += 1; i }), "TiB"),
        (1 << (10 * { i += 1; i }), "PiB"),
        (1 << (10 * { i += 1; i }), "EiB"),
    ]
};

Basically C++'s constexpr is Rust's const, which can be directly defined within a block (no need for the callable trick).

Obviously you can only call const functions (const fn) within its body, and sadly at the moment some numeric functions aren't const yet, such as .pow() or .checked_pow(), hence my using bit shifts here instead. Similarly const blocks are currently still quite limited, and for instance, do not support closures that capture exclusive (&mut) references, hence my having to copy-paste { i += 1; i }.

4 Likes

Strictly speaking Rust const is not direct equivalent of C++ constexpr. C++ constexpr can be evaluated at runtime, but Rust const us guaranteed to be evaluated at compile time.

Wrong information, check below.

@Hyeonu can a constexpr variable be evaluated at runtime? That looks like it would defeat its purpose...

Obviously a constexpr function can be called at runtime, and Rust const fn can also be called at runtime, so in that regard they are similar, I'd say.

2 Likes

Nope, that was my misunderstanding. After quick spec check I figured out that the C++ constexpr is identical with the Rust const. Except the C++ has if constexpr which Rust doesn't have.

1 Like

Thanks for this trick! BTW I believe pow() is const, the signature is

#[inline]
#[rustc_inherit_overflow_checks]
pub const fn pow(self, mut exp: u32) -> Self{...}

You currently need a nightly compiler with #![feature(const_int_pow)] to enable this.

A limitation of const is that you can't use conditionals and loops, which pow needs. This limitation will be fixed but it's currently unstable (aka it's a work in progress). So the standard library can use it internally but has to pretend not to until it's made stable.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.