在编译时计算一组常量表达式的最大值

时间:2018-12-04 18:58:04

标签: rust rust-macros

我正在尝试在Rust程序宏(派生宏)中计算编译时一组常量的最大值。

宏看起来像:

fn get_max_len() -> TokenStream {
    // Each TokenStream represents a constant expression
    let len: Vec<TokenStream> = get_constant_lengths();

    quote! {
      // #(#len),* gets expanded to #len[0], #len[1], #len[2]...
      const LEN: usize = std::cmp::max(#(#len),*);
    }
}

问题在于std::cmp::max是一个函数,因此不能在常量表达式中使用(至少要等到const fn稳定之后,我才能尽可能保持稳定Rust)

在编译时如何计算一组常量的最大值?

我也许可以编写一个max!宏,该宏基本上以递归方式构造大量if链,但我希望那里有一个更干净的解决方案。

1 个答案:

答案 0 :(得分:5)

虽然常量求值不支持if或其他控制流,但是有一种方法可以根据二进制条件选择值:

[a, b][(a < b) as usize]

这是什么

  • 创建要在其中选择的两个元素的数组
  • 创建一个任意的布尔表达式
  • usize
  • 说了一个表达
  • 使用该值索引到上面创建的数组中

如果条件为false,则选择第一个元素;如果条件为true,则选择第二个元素。

虽然该方案理论上可以通过对多个强制转换的bool进行数学运算来计算索引,从而扩展到任意长度的数组,但是,采用函数方法并嵌套上面的表达式似乎更简单:

const fn max(a: usize, b: usize) -> usize {
    [a, b][(a < b) as usize]
}

const MAX: usize = max(max(max(5, 6), 42), 3);

从Rust 1.31开始,const fn在稳定的编译器上可用。