Search code examples
type-conversionconstantsdimmutabilitytype-punning

D preserving constness (DLang)


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

Solution

  • 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.