Removes the outer layer of all type qualifiers from type T - this
includes shared.
If no type qualifiers have been applied to the outer layer of type T,
then the result is T.
For the built-in scalar types (that is bool, the character types, and
the numeric types), they only have one layer, so constU simply becomes
U.
Where the layers come in is pointers and arrays. const(U*) becomes
const(U)*, and const(U[]), becomes const(U)[]. So, a pointer
goes from being fully const to being a mutable pointer to const,
and a dynamic array goes from being fully const to being a mutable
dynamic array of const elements. And if there are multiple layers of
pointers or arrays, it's just that outer layer which is affected - e.g.
shared(U**) would become shared(U*)*.
For user-defined types, the effect is that constU becomes U, and
how that affects member variables depends on the type of the member
variable. If a member variable is explicitly marked with any qualifiers,
then it will continue to have those qualifiers even after Unqualified has
stripped all qualifiers from the containing type. However, if a qualifier
was on the member variable only because the containing type had that
qualifier, then when Unqualified removes the qualifier from the containing
type, it is removed from the member variable as well.
Also, Unqualified has no effect on what a templated type is instantiated
with, so if a templated type is instantiated with a template argument which
has a type qualifier, the template instantiation will not change.
Note that in most cases, Unconst or Unshared should be used
rather than Unqualified, because in most cases, code is not designed to
work with shared and thus doing type checks which remove shared
will allow shared types to pass template constraints when they won't
actually work with the code. And when code is designed to work with
shared, it's often the case that the type checks need to take
const into account in order to avoid accidentally mutating const
data and violating the type system.
In particular, historically, a lot of D code has used
std.traits.Unqual (which is equivalent to phobos.sys.traits'
Unqualified) when the programmer's intent was to remove const, and
shared wasn't actually considered at all. And in such cases, the code
really should use Unconst instead.
But of course, if a template constraint or staticif really needs to
strip off both the mutability qualifiers and shared for what it's
testing for, then that's what Unqualified is for. It's just that it's best
practice to use Unconst when it's not clear that shared should
be removed as well.
Removes the outer layer of all type qualifiers from type T - this includes shared.
If no type qualifiers have been applied to the outer layer of type T, then the result is T.
For the built-in scalar types (that is bool, the character types, and the numeric types), they only have one layer, so const U simply becomes U.
Where the layers come in is pointers and arrays. const(U*) becomes const(U)*, and const(U[]), becomes const(U)[]. So, a pointer goes from being fully const to being a mutable pointer to const, and a dynamic array goes from being fully const to being a mutable dynamic array of const elements. And if there are multiple layers of pointers or arrays, it's just that outer layer which is affected - e.g. shared(U**) would become shared(U*)*.
For user-defined types, the effect is that const U becomes U, and how that affects member variables depends on the type of the member variable. If a member variable is explicitly marked with any qualifiers, then it will continue to have those qualifiers even after Unqualified has stripped all qualifiers from the containing type. However, if a qualifier was on the member variable only because the containing type had that qualifier, then when Unqualified removes the qualifier from the containing type, it is removed from the member variable as well.
Also, Unqualified has no effect on what a templated type is instantiated with, so if a templated type is instantiated with a template argument which has a type qualifier, the template instantiation will not change.
Note that in most cases, Unconst or Unshared should be used rather than Unqualified, because in most cases, code is not designed to work with shared and thus doing type checks which remove shared will allow shared types to pass template constraints when they won't actually work with the code. And when code is designed to work with shared, it's often the case that the type checks need to take const into account in order to avoid accidentally mutating const data and violating the type system.
In particular, historically, a lot of D code has used std.traits.Unqual (which is equivalent to phobos.sys.traits' Unqualified) when the programmer's intent was to remove const, and shared wasn't actually considered at all. And in such cases, the code really should use Unconst instead.
But of course, if a template constraint or static if really needs to strip off both the mutability qualifiers and shared for what it's testing for, then that's what Unqualified is for. It's just that it's best practice to use Unconst when it's not clear that shared should be removed as well.