Search code examples
c++templatesstdtype-traits

Construct C++ Integer type from <number of bytes> and <signedness>


  • I have a constexpr size_t byte_count, which is either 1, 2, 4, or 8
  • I have a constexpr bool is_signed, which is obviously either true or false

I want to construct a typedef/using for an Integer type T with sizeof(T) == byte_count and std::is_signed_v<T> == is_signed.

  1. Is there something in <type_traits> (or elsewhere in the standard library) that does this?

  2. Otherwise, what is the most compact way to achieve this?

  • I'd really like something short that does not hardcode the types since this will be used in multiple places where it's annoying to introduce helper functions/types (it's inside of generated code... sigh).

  • I don't have boost.

My current solution:

#include <type_traits>
#include <tuple>
#include <cstddef>
#include <cstdint>

int main(){
    constexpr size_t byte_count = 4; // either 1, 2, 4, or 8
    constexpr bool is_signed = true; // either true or false

    // I would like to have something shorter and less hardcoded than this
    using T = std::conditional_t<
        is_signed,
        std::tuple_element_t<byte_count, std::tuple<int8_t, int16_t, int16_t, int32_t, int32_t, int32_t, int32_t, int64_t>>,
        std::tuple_element_t<byte_count, std::tuple<uint8_t, uint16_t, uint16_t, uint32_t, uint32_t, uint32_t, uint32_t, uint64_t>>
    >;

    static_assert(sizeof(T) == byte_count);
    static_assert(std::is_signed_v<T> == is_signed);
}

Solution

  • There is nothing in the C++ standard library that will do this. Unfortunately, you will have to implement the mapping yourself.

    You can use std::make_signed_t to get rid of half of the cases.

    Something like this:

    template<std::size_t ByteWidth>
    struct select_uint;
    
    template<> struct select_uint<1> { using type = std::uint8_t; };
    template<> struct select_uint<2> { using type = std::uint16_t; };
    template<> struct select_uint<4> { using type = std::uint32_t; };
    template<> struct select_uint<8> { using type = std::uint64_t; };
    
    template<std::size_t ByteWidth, bool IsSigned>
    using select_int_t = std::conditional_t<IsSigned,
        std::make_signed_t<typename select_uint<ByteWidth>::type>,
        typename select_uint<ByteWidth>::type>;