I would (1) like to declare an unsigned integer that has the same size as the given typename or type of a given expression, and (2) provide a type conversion to that type that simply passes the bitpattern of the argument unchanged. (Even in the case of passing a float, say, I need it converted to a uint of the correct width that preserves the bitpattern faithfully.)
How should I deal with preserving the constness of the type unchanged, in both cases, not casting away const or immutable?
Here's my partial attempt:
template TUint_t( alias T )
{
static if ( T.sizeof * 8 == 64 )
alias TUint_t = uint64_t;
else static if ( T.sizeof * 8 == 32 )
alias TUint_t = uint32_t;
else static if ( T.sizeof * 8 == 16 )
alias TUint_t = uint16_t;
else static if ( T.sizeof * 8 == 8 )
alias TUint_t = uint8_t;
else static assert ( false );
}
auto ConvertToBitPattern( T )( inout T x )
{
return * cast( TUint_t!(T) * ) &x;
}
Use std.traits.CopyConstness
, which returns the second type parameter with the const-ness qualifier of the first.
template TUint_t( alias T )
{
static if ( T.sizeof * 8 == 64 )
alias U = uint64_t;
else static if ( T.sizeof * 8 == 32 )
alias U = uint32_t;
else static if ( T.sizeof * 8 == 16 )
alias U = uint16_t;
else static if ( T.sizeof * 8 == 8 )
alias U = uint8_t;
else static assert ( false );
// Apply T's const-ness to U
alias TUint_t = CopyConstness!(T, U);
}
Note: this does not copy shared
. std.traits.CopyTypeQualifiers
will copy const and shared-ness.