0
votes

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;
    }
1

1 Answers

4
votes

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.