Container with different const generic elements

Dear all,

I am looking for a container that can handle elements of the same type, but with different const generics:

struct Element<const N: usize> {
    data: [f64; N],
}

I understand that vectors don't/can't work, since they require every element to be of the same size. But I would also be totally fine with Box or pointers.

I think this question summerizes the alternatives for arbitrary types quite well, but 1. I don't necessarily need the container to be a vector; 2. enums won't help since I can't create a variant for each usize out there; 3. maybe there is another way, since I'm having the same type with different const generics?

Thanks in advance!

Best,
welahi

1 Like

There is one way to construct such a value, and that is by abstracting over the const-parameterized type with a trait, and casting the values of those related types to &dyn Trait. Note that that will accordingly be eg Vec<&dyn Trait> rather than Vec<MyType<_>> for some type struct MyType<const N: usize> { ... }.

The reason is that types with different values for const generic parameters are, to rustc at least, completely different types. MyType<0> and MyType<1> are as much different types as e.g. bool and String are.

EDIT: there is a 2nd way, by using an enum to wrap all the related types, with one enum variant per type.
This may or may not be viable; if the const param could be any number (i.e. the set of types is open) then wrapping it in an enum won't work. But if there are eg just a handful of such types that need to be considered, then it might be an option.

2 Likes

To expand @jjpe answer, here is a minimal example of using trait objects:

struct E<const N: usize>;

trait Foo { 
    fn n(&self) -> usize;
}

impl<const N: usize> Foo for E<N> {
    fn n(&self) -> usize {
        N
    }
}

struct Container {
    inner: Vec<Box<dyn Foo>>,
}

fn main() {
    let c = Container {
        inner: vec![Box::new(E::<0>), Box::new(E::<1>)],
    };
    
    assert_eq!(c.inner[0].n(), 0);
    assert_eq!(c.inner[1].n(), 1);
}

Playground.

3 Likes

Sorry for the late reply, thank you both for your answers!

I think I'll go then with a hybrid approach, i.e. specifying enum-variants for like N=1,...,10, and then adding a last variant with dyn. It's a bit messy but probably the best solution to my problem :slight_smile:

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.