在编译时计算一组常量表达式的最大值
Posted
技术标签:
【中文标题】在编译时计算一组常量表达式的最大值【英文标题】:Calculating maximum value of a set of constant expressions at compile time 【发布时间】:2019-05-06 06:40:52 【问题描述】:我试图在编译时计算 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
s 链,但我希望有一个更简洁的解决方案。
【问题讨论】:
为什么不只评估max
outside 的quote
宏调用,只把结果值放在里面?
不幸的是,这种情况下的常量通常是来自接口的关联常量,因此我无法直接访问该值 - 我所拥有的是将编译器作为常量评估的表达式。为了计算出这些值,我必须实现一个可以提取值的评估器,在某些情况下是递归的,这是不可行的。
if
s 的巨大链 — if
目前也不允许在常量表达式中使用;你是这个意思吗?
是的,这就是我的意思——如果不允许,我完全没有想法......
您可以使用[a, b][(a < b) as usize]
在编译时计算两个值的最大值。我将把它留给读者从 sn-p 到更多元素的通用解决方案。
【参考方案1】:
虽然常量评估不支持if
或其他控制流,但有一种方法可以根据二进制条件选择值:
[a, b][(a < b) as usize]
这是做什么的
创建一个包含您要在其中选择的两个元素的数组 创建任意布尔表达式 将所述表达式转换为usize
使用该值索引到上面创建的数组中
如果条件为false
,则选择第一个元素,如果条件为true
,则选择第二个元素。
虽然该方案理论上可以通过对多个转换的bool
s 进行数学运算来计算索引,从而扩展到任意长度的数组,但采用函数式方法并嵌套上述表达式似乎更简单:
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
可用于稳定的编译器。
【讨论】:
以上是关于在编译时计算一组常量表达式的最大值的主要内容,如果未能解决你的问题,请参考以下文章