How to make a const parameter generic?

I have this code

struct Min<T, const N: usize>(T, PhantomData<usize>);

But N isn't always a usize. I tried passing N: T to make N could accept any numeric type like this, but it didn't work

struct Min<T, const N: T>(T, PhantomData<T>);

Is there a way to do this?

struct Min<U, T : trait_that_implements_nemeric>(U, PhantomData<T>);

your code works, but if you don't use N const, it is better use a type instead

The feature you are looking for is known as generic_const_parameter_types. It is desired, but not implemented at all, nor even fully designed, yet.

This isn't really a full solution, but what you want can perhaps be got through a trait?

trait MinConst
{
  type ConstType: Num; // from the `num` crate perhaps
  const CONST_VALUE: <Self as MinConst>::ConstType;
}
struct Min<T: Num, U: MinConst<ConstType = T> + ?Sized>(T, PhantomData<U>);

Note how only const generics can become const generics and array size/repeat arguments so this probably doesn't solve your problem.

Thanks everyone for the answers. Everything is running smoothly now. However, I’m still looking for a way to achieve the same effect as const N: T to avoid the runtime .into() conversion seen in this code

use std::marker::PhantomData;

trait Validator<T> {
    fn validate(val: &T) -> Result<(), &'static str>;
}

struct Validated<T, V: Validator<T>>(T, PhantomData<V>);

impl<T, V: Validator<T>> Validated<T, V> {
    fn new(val: T) -> Result<Self, &'static str> {
        V::validate(&val)?;
        Ok(Self(val, PhantomData))
    }
    
    fn get(&self) -> &T {
        &self.0
    }
    
    fn take(self) -> T {
        self.0
    }
}

struct Min<const N: i128>;
impl<T, const N: i128> Validator<T> for Min<N> 
where T: PartialOrd + Copy + Into<i128> {
    fn validate(val: &T) -> Result<(), &'static str> {
        if (*val).into() >= N {
            return Ok(());
        }
        Err("Value too small")
    }
}

struct Tes {
    val: Validated<i32, Min<10>>
}

fn main() -> Result<(), &'static str> {

    let tes = Tes {
        val: Validated::new(20)?
    };
    
    println!("{}", tes.val.take());
    
    Ok(())
}

Does anyone know how to do that?

Hey, I found this way. Which one is better?

use std::marker::PhantomData;

trait Validator<T> {
    fn validate(val: &T) -> Result<(), &'static str>;
}

struct Validated<T, V: Validator<T>>(T, PhantomData<V>);

impl<T, V: Validator<T>> Validated<T, V> {
    fn new(val: T) -> Result<Self, &'static str> {
        V::validate(&val)?;
        Ok(Self(val, PhantomData))
    }
    
    fn get(&self) -> &T {
        &self.0
    }
    
    fn take(self) -> T {
        self.0
    }
}

trait Num<T> {
    const val: T;
}

struct Min<N>(PhantomData<N>);
impl<T, N> Validator<T> for Min<N> 
where 
    T: PartialOrd + Copy,
    N: Num<T>
{
    fn validate(val: &T) -> Result<(), &'static str> {
        if *val >= N::val {
            return Ok(());
        }
        Err("Value too small")
    }
}

struct Tes {
    val: Validated<i32, Min<Numm>>
}

struct Numm;
impl Num<i32> for Numm {
    const val: i32 = 10;
}

fn main() -> Result<(), &'static str> {

    let tes = Tes {
        val: Validated::new(20)?
    };
    
    println!("{}", tes.val.take());
   
    Ok(())
}