🤔

定数パラメタの制限

2023/03/22に公開

たとえばこんな C++ のコードがあったとする。

#include <cstddef>

template <class T, std::size_t n>
struct foo {
    T data[n + 1];
    foo(void) {}
};

int main(void) {
    auto obj = foo<int, 10>();
}

Rust にベタ移植するなら以下のような形だろう……が、実際にはこれはコンパイルできない。

#[derive(Clone)]
struct Foo<T, const N: usize> {
    data: [T; { N + 1 }],
}

impl<T: Copy + Default, const N: usize> Foo<T, N> {
    fn new() -> Self {
        Foo::<T, N> {
            data: [T::default(); { N + 1 }],
        }
    }
}

fn main() {
    let obj = Foo::<u32, 10>::new();
}

定数パラメータは型に使うときは単独 (standalone) である必要があるという制限が付いているからだ。 なんの計算も出来ずにそのまま渡さなければいけない。

使い方が変わらないようにワークアラウンドを考えるとしたらこんな感じだろうか。

#[derive(Clone)]
struct Foo<T, const N: usize> {
    data: Vec<T>,
}

impl<T: Copy + Default, const N: usize> Foo<T, N> {
    fn new() -> Self {
        Foo::<T, N> {
            data: {
                let mut v = Vec::with_capacity(N + 1);
                v.resize(N + 1, T::default());
                v
            },
        }
    }
}

fn main() {
    let obj = Foo::<u32, 10>::new();
}

コンパイル時に配列の大きさはわかっているのにそのまま表現できないのがもどかしく感じる。

Discussion