In Rust you can implement traits for structs and each implementation has own type constraint. (for who may does not familiar with rust, you can consider a "trait" as a "base class" and "implementation" as "inheritance"). look at this example:
// our struct has an item of type mutable T pointer
struct Box<T> {
inner: mut* T
}
// implementing `Default` trait for
// box. in this implementation, type
// constraint is: `T: Default`.
// it means the inner type also must
// implements Default.
impl <T: Default> for Box<T> {
fn default() -> Self {
return Box::new(T::default());
}
}
the note in this example is there is no need T: Default
to be applied until you use Box::default()
in your code.
well it is possible to do like this in cpp? I'm familiar with how we can constraint types in cpp and this is not my problem. I want to know is there some way to lazy type constrain
(maybe a better description) in cpp when I define a class?
I know it is possible with if constexpr
or static_assert
. but this way is not beautiful.
I want a template
or concept
solution ( I mean what applies to function signature in fact) if possible.
thank you for any guidance.
I am not sure I follow exactly what you want (I don't really know Rust), but you can constrain member functions individually:
template<typename T>
concept Default = requires {
{ T::default_() } -> std::same_as<T>;
};
template<typename T>
struct Box {
static Box default_()
requires Default<T> {
//...
}
//...
};
Now Box
itself has no requirements on T
, but to use Box::default()
will require T
to satisfy the Default
concept.
However, it would basically work without the constraint as well. If Box<T>::default
calls T::default()
and the latter is not well-formed the code will fail to compile if and only if Box<T>::default
is actually used in a way that requires it to be defined (i.e. called or pointer/reference to it taken). But without the requires
clause e.g. Default<Box<T>>
would always report true
.
And of course in C++ we would use the default constructor instead of a static member function called default
to construct the object. The same approach applies to constructors though and there is already the concept std::default_initializable
for that in the standard library.
As far as I understand, Rust traits do not really overlap fully with either C++ (abstract) base classes nor concepts though. The approach above will not allow for runtime polymorphism on types satisfying Default
. For that an abstract base class with the interface functions as non-static pure virtual member functions should be used instead.
However, the trait Default
only imposes a requirement on a static member function, so that it shouldn't be relevant to runtime polymorphism, but only compile-time properties of the type, which is what concepts are for, although in contrast to Rust you don't declare a type to implement a trait. Instead the concept describes requirements which a type needs to satisfy to satisfy the concept.