Trait
Traits are classes containing unimplemented methods, while you can provide default impls:
trait Unsigned(T: Type) { assert(IsUnsigned(T.value)); def asUint64(self): u64 = staticCast(u64, self.value);}
trait Unsigned(T: Type) { assert(IsUnsigned(T.value)); def asUint64(self): u64 = staticCast(u64, self.value);}
template <typename T>struct UnsignedConcept { virtual uint64_t asUint64() = 0; virtual ~UnsignedConcept() = default;};template <typename T>struct UnsignedModel: public UnsignedConcept<T> { T& self; UnsignedModel(T& self) : self(self) { static_assert(IsUnsigned<T::ValueT>::value); } uint64_t asUint64() override { return static_cast<uint64_t>(self.value); }};
template <typename T>struct UnsignedConcept { virtual uint64_t asUint64() = 0; virtual ~UnsignedConcept() = default;};template <typename T>struct UnsignedModel: public UnsignedConcept<T> { T& self; UnsignedModel(T& self) : self(self) { static_assert(IsUnsigned<T::ValueT>::value); } uint64_t asUint64() override { return static_cast<uint64_t>(self.value); }};
As you see, traits are dispatched in some C++ magic concepts.
impl(T <: U32 | U16 | U8) Unsigned(T) for T { def asUint64(self): u64 = staticCast(u64, self);}
impl(T <: U32 | U16 | U8) Unsigned(T) for T { def asUint64(self): u64 = staticCast(u64, self);}
template <typename T, typename Cond>struct TModel;template <typename T>struct TModel<T, std::enable_if<std::is_same<T, uint32_t | uint16_t | uint8_t>>>: public UnsignedConcept<T> { T& self; UnsignedModel(T& self) : self(self) { } uint64_t asUint64() override { return static_cast<uint64_t>(self); }};
template <typename T, typename Cond>struct TModel;template <typename T>struct TModel<T, std::enable_if<std::is_same<T, uint32_t | uint16_t | uint8_t>>>: public UnsignedConcept<T> { T& self; UnsignedModel(T& self) : self(self) { } uint64_t asUint64() override { return static_cast<uint64_t>(self); }};
Templated implimpl introduces challenge on trait method resolving. Users who gets interested in this feature can check Rust: Trait solving.