this is probably an XY problem, the solution you are seeking doesn't seem to solve any practical problem. please describe the problem itself instead of the solution you want to approach.
anyway, you can kind of achieve something similar, but it doesn't add real value, it can only be used as some marker bounds.
first, let's see a failed attemp: this code won't compile due to conflicting blanket impls, as the type checker has no way to understand T: Signed
and T: Unsigned
are non-overlapping.
trait MyTrait {
const SIGNED: bool;
}
impl<T> MyTrait for T where T: Signed {
const SIGNED: bool = true;
}
impl<T> MyTrait for T where T: Unsigned {
const SIGNED: bool = false;
}
this code, however, does compile because a trait with (const or type, doesn't matter) generic parameters is NOT one single trait per se, but rather a family of traits, and you are adding impls for different member of that family.
trait MyTrait<const SIGNED: bool> {}
impl<T> MyTrait <true> for T where T: Signed {}
impl<T> MyTrait<false> for T where T: Unsigned {}
I don't see any means for this to be useful in generic code, except using it as an marker. the trait itself doesn't define any meaningful generic interface; you must repeat the const generic argument wherever you use the trait in your generic code; besides, since Signed
and Unsigned
support different operations, your "generic" code isn't really generic at all! you still need to figure out some way to dispatch based on whether it's Signed
or Unsigned
:
// !!!!!! don't do this !!!!!!
struct Foo<const SIGNED: bool, T: I32_or_U32<SIGNED>> {
//...
}
impl <const SIGNED: bool, T: I32_or_U32<SIGNED>> Foo<SIGNED, T> {
fn signed_calcuation(&self) -> Option<T> {
// this function uses signed operations
if !SIGNED {
return None;
}
todo!()
}
fn unsigned_calculation(&self) -> Option<T> {
// this function uses unsigned operations
if SIGNED {
return None;
}
todo!()
}
}
instead, just use the Signed
and Unsigned
trait directly when your generic code needs certain operations, it is much cleaner:
struct Foo<T> {
//...
}
impl<T> Foo<T> {
fn new(foo: T) -> Self where T: Num {
Self {
//...
}
}
fn bar(&self) -> T where T: Signed {
todo!()
}
fn baz(&self) -> T where T: Unsigned {
todo!()
}
}