Const generics: how to impl "not equal"

For example, I have a type like this:

struct Foo<const I: i32> {}

And I want to implement a function for types which I does not equal to "0", but I don't know how to write the code, I tried this:

struct Foo<const I: bool> {

}

impl<const I: bool> Foo<I> where I != 0 {
    fn foo() -> SomeTypeA {}
}

impl<const I: bool> Foo<I> where I == 0 {
    fn foo() -> SomeTypeB {}
    fn some_function_only_exists_in_I_eq_0() {}
}

But failed.

Any idea?

P.S. Nightly features are also acceptable.

struct Foo<const I: i32> {}

impl<const I: i32> Foo<I> {
    const CHECK: bool = I != 0;

    const fn f() {
        if Self::CHECK {
        } else {
            unreachable!()
        }
    }
}

fn main() {
    assert!(!Foo::<0>::CHECK);
    assert!(Foo::<1>::CHECK);
    Foo::<2>::f();
}

Thanks for helping, but this solution is not exactly what I want, I updated my question, in this case, the feature "panic in const" does not help.

I cooked up this monstrosity.

#![feature(generic_const_exprs)]
#![allow(incomplete_features)]

pub struct Foo<const I: i32> {}

impl<const I: i32> Foo<I>
where
    Boolean<{ is_zero(I) }>: Marker,
{
    pub fn new() -> Self {
        Foo {}
    }
}

fn main() {
    let a: Foo<1> = Foo::new();
    let b: Foo<0> = Foo::new();
}

struct Boolean<const B: bool>;

const fn is_zero(n: i32) -> bool {
    n == 0
}

trait Marker {}
impl Marker for Boolean<false> {}

(playground)

It correctly points to the b line as an error:

   Compiling playground v0.0.1 (/playground)
error[E0599]: the function or associated item `new` exists for struct `Foo<0_i32>`, but its trait bounds were not satisfied
  --> src/main.rs:17:23
   |
4  | pub struct Foo<const I: i32> {}
   | ---------------------------- function or associated item `new` not found for this
...
17 |     let b = Foo::<0>::new();
   |                       ^^^ function or associated item cannot be called on `Foo<0_i32>` due to unsatisfied trait bounds
...
20 | struct Boolean<const B: bool>;
   | ------------------------------ doesn't satisfy `Boolean<{ is_zero(I) }>: Marker`
   |
   = note: the following trait bounds were not satisfied:
           `Boolean<{ is_zero(I) }>: Marker`
note: the following trait must be implemented
  --> src/main.rs:26:1
   |
26 | trait Marker {}
   | ^^^^^^^^^^^^^^^
4 Likes
struct Foo<const I: i32> {}

impl<const I: i32> Foo<I> {
    fn foo() -> Self {
        Foo {}
    }
}

impl Foo<0> {
    fn some_function_only_exists_in_I_eq_0() {}
}

fn main() {
    Foo::<0>::some_function_only_exists_in_I_eq_0();
    Foo::<1>::some_function_only_exists_in_I_eq_0();
}

playground

Error:

error[E0599]: no function or associated item named `some_function_only_exists_in_I_eq_0` found for struct `Foo<1_i32>` in the current scope
  --> src/main.rs:15:15
   |
1  | struct Foo<const I: i32> {}
   | ------------------------ function or associated item `some_function_only_exists_in_I_eq_0` not found for this
...
15 |     Foo::<1>::some_function_only_exists_in_I_eq_0();
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item not found in `Foo<1_i32>`
   |
   = note: the function or associated item was found for
           - `Foo<0_i32>`

Hi, it looks that the playground report a totally different error, so do my compiler, is there any doc talks about this { is_zero(I)} feature, I somehow understand what you are trying to do.

If you want to use const expressions (i.e. call is_zero() with the I const) then you need to wrap it in curly braces so it doesn't get parsed as a type. Evaluating const expressions in generics is still very incomplete, so your best bet is to check the PR or RFC associated with generic_const_exprs.

1 Like
struct Item<const I: u8>;
#[derive(Debug)] struct A;
#[derive(Debug)] struct B;
#[derive(Debug)] struct C;

impl Item<0> { fn foo() -> A { A } }
impl Item<1> { fn foo() -> B { B } }
impl Item<2> { fn foo() -> C { C } }

const fn check(i: i32) -> u8 {
    match i {
        0   => 0,
        1.. => 1,
        _   => 2,
    }
}

fn main() {
    dbg!(Item::<{ check(0) }>::foo(),   // A
         Item::<{ check(1) }>::foo(),   // B
         Item::<{ check(-1) }>::foo()); // C
}

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.