Const N: usize, const M: usize, require that N >= M?

Suppose we have a function that takes generic parameters (not arguments)

const N: usize
const M: usize

is it possible to require constraints at COMPILE TIME of the form N >= M or N, M are powers of 2 ... ?

On stable, no. Using the type-level-booleans trick and the definitely-not-stable generic_const_expr feature on nightly, yes:

#![feature(generic_const_exprs)]

trait True {}
struct Test<const B: bool>;
impl True for Test<true> {}

fn foo<const N: usize, const M: usize>()
where 
    Test<{N < M}>: True 
{

}

fn main() {
    foo::<4, 5>();  // Ok
    foo::<5, 4>();  // Does not compile
}

Playground

6 Likes

For the powers of two you could just change your API to accept the base2 logarithm of the numbers (so 1 instead of 2, 5 instead of 32 etc) — inside your code itself 2.pow(N) will definitely get const-folded to its real value so there’s no runtime cost. Similarly instead of accepting N and M you can accept M and the difference between the two values, so that invalid states aren’t representable (and again it will not have performance impact). But these solutions don’t always lead to the cleanest API.

4 Likes

There is a stable work-around:

12 Likes

Using unstable, I have seen this, which might be easier to use in some circumstances:

#![feature(generic_const_exprs)]

fn foo<const N: usize, const M: usize>()
where 
    [(); M-N-1]:, 
{

}

fn main() {
    foo::<4, 5>();  // Ok
    foo::<5, 4>();  // Does not compile
}

(Playground)

Note this ensures M > N. If you want M >= N, omit the -1.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.