4
  • 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);
}
ChrisB
  • 1,540
  • 6
  • 20
  • No idea, have an upvote from me. – john May 11 '23 at 16:17
  • wasn't me, but answer already was on SO, that's probably the reason (lack of research). You have types in `` and you can do specialization, – Swift - Friday Pie May 11 '23 at 16:18
  • Why do you need it? What is the *actual* and *underlying* problem this would solve? Please ask about that problem directly instead, otherwise your question unfortunately is just another [XY problem](https://en.wikipedia.org/wiki/XY_problem). – Some programmer dude May 11 '23 at 16:19
  • @Someprogrammerdude: this is inside of templated unit test code, and I need to construct a type based on properties of another type to call a templated function with in the end. The framework can't be changed by me, so this is absolutely the problem, and not a symptom/side effect. – ChrisB May 11 '23 at 16:42

3 Answers3

7

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>;
Artyer
  • 31,034
  • 3
  • 47
  • 75
2

I don't think you can do much better than explicitly listing all of your types.

This could look something like:

template <int size, bool is_signed>
struct int_traits;

template <>
struct int_traits<1, false> { using type = uint8_t; };
template <>
struct int_traits<1, true> { using type = int8_t; };
template <>
struct int_traits<2, false> { using type = uint16_t; };
template <>
struct int_traits<2, true> { using type = int16_t; };

template <int size, bool is_signed>
using int_t = typename int_traits<size, is_signed>::type;

int main()
{
    int_t<1, true> b = 1;
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • The `using` statement needs to use `typename` since it is aliasing a type that is dependant on the template arguments, eg: `using int_t = typename int_traits::type;` See https://stackoverflow.com/questions/610245/ – Remy Lebeau May 11 '23 at 17:47
2

You are going to have to list out the type, but you can use a helper function to make that easier to do. That could look like

template <std::size_t bytes, bool is_signed>
auto int_type()
{
    if constexpr (bytes == 1 && is_signed)       return int8_t{};
    else if constexpr (bytes == 1)               return uint8_t{};
    else if constexpr (bytes == 2 && is_signed)  return int16_t{};
    else if constexpr (bytes == 2)               return uint16_t{};
    else if constexpr (bytes == 4 && is_signed)  return int32_t{};
    else if constexpr (bytes == 4)               return uint32_t{};
    else if constexpr (bytes == 8 && is_signed)  return int64_t{};
    else if constexpr (bytes == 8)               return uint64_t{};
    else                                         return; // void for the error case
}

template <std::size_t bytes, bool is_signed>
using int_type_t = decltype(int_type<bytes, is_signed>());

int main()
{
    int_type_t<1, true> b = 1;
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402