Отображение значения параметра интегрального шаблона на примитивный тип - PullRequest
0 голосов
/ 26 ноября 2018

Я хочу сопоставить число типу.Для этого примера я сделаю функцию, которая отображает результат sizeof () на подписанный примитивный тип.

Мне интересно, есть ли лучший способ сделать то, что я сделал ниже в современном C ++, то естьвзять шаблонное значение и преобразовать его в тип.Сейчас это работает при преобразовании размера в известный тип, но я не могу найти ничего в стандартной библиотеке, которая делает то, что я хочу.Я что-то пропустил?

Если нет, есть ли лучший способ сделать это или очистить этот код?Например, если в будущем мы получим 128-битные типы, это не будет поддерживаться.

#include <iostream>
#include <type_traits>

template <size_t S>
static constexpr auto sizeToType() {
    static_assert(S == 1 or S == 2 or S == 4 or S == 8, "Bad type size");

    if constexpr (S == 1)
        return int8_t{};
    else if constexpr (S == 2)
        return int16_t{};
    else if constexpr (S == 4)
        return int32_t{}; 
    else
        return int64_t{};
}

int main() {
    using MY_TYPE = decltype(sizeToType<2>());

    MY_TYPE myType = MY_TYPE(0xFFFFFFFFFFFFFFFEUL);

    std::cout << sizeof(MY_TYPE) << " bytes" << std::endl;
    std::cout << "MY_TYPE(0xFFFFFFFFFFFFFFFEUL) = " << myType << std::endl;
}

Вывод (как и ожидалось):

2 bytes
MY_TYPE(0xFFFFFFFFFFFFFFFEUL) = -2

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Не лучшее решение ... но просто для удовольствия ...

Я предлагаю черты типа (с помощником и с помощью выбора внутреннего типа), которые, учитывая число (количество байтов)и список типов выбирает первый тип списка с sizeof() большим или равным (или ничем, если такого типа нет)

template <std::size_t, typename, typename = std::true_type>
struct sizeTypeH;

template <std::size_t Dim>
struct sizeTypeH<Dim, std::tuple<>, std::true_type>
 { };  // no type found

template <std::size_t Dim, typename T0, typename ... Ts>
struct sizeTypeH<Dim, std::tuple<T0, Ts...>,
                 std::integral_constant<bool, (sizeof(T0) >= Dim)>>
 { using type = T0; };

template <std::size_t Dim, typename T0, typename ... Ts>
struct sizeTypeH<Dim, std::tuple<T0, Ts...>,
                 std::integral_constant<bool, (sizeof(T0) < Dim)>>
   : public sizeTypeH<Dim, std::tuple<Ts...>>
 { };

template <std::size_t Dim, typename ... Ts>
struct sizeType : public sizeTypeH<Dim, std::tuple<Ts...>>
 { };

template <std::size_t Dim, typename ... Ts>
using sizeType_t = typename sizeType<Dim, Ts...>::type;

Теперь еще один using, который, получив целое число, вызываетчерты этого типа с упорядоченным списком intX_t типов

template <std::size_t Dim>
using intType_t = sizeType_t<Dim, std::int8_t, std::int16_t, std::int32_t,
                             std::int64_t>;

В моей платформе у меня есть следующие проверенные static_assert().

   using t8  = intType_t<1u>;
   using t16 = intType_t<2u>;
   using t32 = intType_t<4u>;
   using t64 = intType_t<8u>;

   static_assert( std::is_same<t8, std::int8_t>{}, "!" );
   static_assert( std::is_same<t16, std::int16_t>{}, "!" );
   static_assert( std::is_same<t32, std::int32_t>{}, "!" );
   static_assert( std::is_same<t64, std::int64_t>{}, "!" );

Если завтра появитсяa int128_t, вы можете просто добавить его в intType_t using определении.

Внимание, пожалуйста: нет никаких гарантий, что предыдущие static_assert() будут выполнены.

First ofвсе потому, что стандарт гарантирует, что байт имеет длину не менее 8 бит;но может быть больше 8 бит.Если байт имеет 16 бит, то из

using t16 = intType_t<2u>;

вы получите тип 32 бит.

Второй, поскольку типы intX_t являются дополнительными.

0 голосов
/ 26 ноября 2018

Я бы не использовал C ++ 17 if constexpr для этого, вместо этого я бы использовал специализацию шаблонов, так как она выглядит для меня более декларативно.

Что-то вроде следующего:

template<size_t S> struct SizeToType {static_assert(S != S, "Wrong size"); };

template<> struct SizeToType<1> { using type = uint8_t; };
template<> struct SizeToType<2> { using type = uint16_t; };
template<> struct SizeToType<4> { using type = uint32_t; };
template<> struct SizeToType<8> { using type = uint64_t; };

template<size_t S>
using SizeToToTypeT = typename SizeToType<S>::type;

Добавление большего количества типов будет означать просто добавление большего количества специализаций (однострочников).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...