2

I believe that the following code makes sense:

trait FooConst<const N: usize> {}
trait Foo {}

impl<T: FooConst<N>, const N: usize> Foo for T {}

However when I try to compile it I get error E0207 stating that the parameter N is unbounded. I don't understand why, since it seems to me that it's part of the bound on T.

Playground link

JoeyBF
  • 123
  • 4

2 Answers2

8

The fundamental reason why this is not allowed is because the trait bounds may cause multiple trait implementations for the same type.

For example, consider a type Bar that implements both FooConst<1> and FooConst<2>, which is perfectly fine:

struct Bar;

impl FooConst<1> for Bar {}
impl FooConst<2> for Bar {}

If Foo is implemented for all T: FooConst<N>, then we get two Foo implementations for Bar: one for N == 1 and one for N == 2. Rust does not allow the possibility of having multiple trait implementations, which is why it disallows using type parameters in this way.

One way to work around this is to instead make N an associated constant:

trait FooConst {
    const N: usize;
}
trait Foo {}

impl<T: FooConst> Foo for T {
    // T::N is an associated constant   
}
Frxstrem
  • 38,761
  • 9
  • 79
  • 119
  • You're right, I wasn't thinking about the possibility that a type might implement the trait for multiple `N`. Actually now that I'm looking into it, it sounds like associated constants might be more appropriate for my use case. Thanks! – JoeyBF Nov 13 '21 at 04:43
1

Ok, so I do not exactly know why this works while your code does not work, but here's a code that does what you want :

trait FooConst<const N: usize> {}
trait Foo {}

impl<const N: usize> Foo for dyn FooConst<N> {}

Feel free leaving a comment if you know why this works.

Naeio
  • 1,112
  • 7
  • 21
  • 1
    I think it's because `dyn FooConst` cannot implement `FooConst` for any other `M`, so the problem in the other answer is not an issue. – JoeyBF Nov 13 '21 at 04:47