QuaternionsRock
QuaternionsRock

Reputation: 922

How to avoid "unconstrained generic constant" with dependent associated constants in traits?

I am in the process of writing a trait with two associated constants: the first is a usize, and the other is an array of usize where with a length equal to the first constant. Essentially, my trait is equivalent to the following:

#![feature(const_trait_impl)]
#![feature(generic_const_exprs)]

trait Foo {
    const SIZE: usize;
    const ARR: [usize; Self::SIZE];
}

struct S;

impl const Foo for S {
    const SIZE: usize = 2;
    const ARR: [usize; Self::SIZE] = [1, 2];
}

fn main() {
    const TEST: &[usize; 2] = &S::ARR;
    println!("{:?}", TEST);
}

As of the current nightly build, this trait definition produces the following error:

error: unconstrained generic constant
 --> src\main.rs:6:5
  |
6 |     const ARR: [usize; Self::SIZE];
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: try adding a `where` bound using this expression: `where [(); Self::SIZE]:`

Unfortunately, the suggested fix is not useful because any where bound involving Self::SIZE would be infinitely recursive. I was ready to give up until I discovered an alternative that seems to work:

#![feature(const_trait_impl)]
#![feature(generic_const_exprs)]

trait Bar {
    const SIZE: usize;
    fn arr() -> [usize; Self::SIZE];
}

struct S;

impl const Bar for S {
    const SIZE: usize = 2;

    fn arr() -> [usize; Self::SIZE] {
        [1,2]
    }
}

fn main() {
    const TEST: &[usize; 2] = &S::arr();
    println!("{:?}", TEST);
}

I am rather perplexed by this discrepancy, all things considered. Is there any way around it, or is it mostly just a matter of waiting for const language support to improve?

Upvotes: 6

Views: 565

Answers (1)

StatPhy
StatPhy

Reputation: 191

You can do as follows

trait Foo<const N : usize>{
    const ARR : [usize; N];
}

struct S;

impl Foo<2> for S{
    const ARR : [usize; 2] = [1, 2];
}

impl Foo<3> for S{
    const ARR : [usize; 3] = [1, 2, 3];
}

fn main(){
    const TEST : &[usize; 2] = &S::ARR;
    println!("{:?}", TEST);  // [1, 2]

    const TEST2 : &[usize; 3] = &S::ARR;
    println!("{:?}", TEST2);  // [1, 2, 3]
}

Upvotes: 1

Related Questions