Альтернативы многим вложенным std :: conditional_t? - PullRequest
0 голосов
/ 30 августа 2018

Я нахожу много вложенных std :: conditional_t ​​трудными для чтения, поэтому я выбираю другой шаблон (вызова decltype для функции с типом автоматического возврата):

template<bool is_signed, std::size_t has_sizeof>
auto find_int_type(){
    static_assert(sizeof(int)==4);
    if constexpr(is_signed){
        if constexpr(has_sizeof==4){
            return int{};
        } else if constexpr (has_sizeof==8){
            return std::int64_t{};
        } else {
            return;
        }
    } else {
        if constexpr(has_sizeof==4){
            return (unsigned int){};
        }
        else if constexpr (has_sizeof==8){
            return std::uint64_t{};
        } else {
            return;
        }
    } 
}

static_assert(std::is_same_v<int, decltype(find_int_type<true, 4>())>);
static_assert(std::is_same_v<unsigned int, decltype(find_int_type<false, 4>())>);
static_assert(std::is_same_v<void, decltype(find_int_type<false, 3>())>);
static_assert(std::is_same_v<void, decltype(find_int_type<false, 5>())>);
static_assert(std::is_same_v<std::int64_t, decltype(find_int_type<true, 8>())>);
static_assert(std::is_same_v<std::uint64_t, decltype(find_int_type<false, 8>())>);
static_assert(std::is_same_v<void, decltype(find_int_type<false, 9>())>);

Мои вопросы:

Есть ли лучший способ?

Этот способ компилируется медленнее, чем std :: conditional_t ​​(если предположить, что типы, которые мне нужно создать, гораздо шире, чем в этом примере, где я просто использую встроенные типы).

P.S. это игрушечный пример, IRCode Я бы имел дело с некоторыми более сложными типами.

Ответы [ 2 ]

0 голосов
/ 30 августа 2018

Поскольку std::disjunction<Args...> наследуется от первого типа в Args..., чей value равен true, или если такого типа не существует, последний тип в Args..., мы можем (ab) использовать его для получения многоходовое отделение:

template<class... Args>
using select = typename std::disjunction<Args...>::type;

template<bool V, class T>
struct when {
    static constexpr bool value = V;
    using type = T;
};

template<bool is_signed, std::size_t has_sizeof>
using find_int_type = select<
    when<is_signed, select<
        when<has_sizeof==4, int>,
        when<has_sizeof==8, std::int64_t>,
        when<false, void>
    >>,
    when<!is_signed, select<
        when<has_sizeof==4, unsigned int>,
        when<has_sizeof==8, std::uint64_t>,
        when<false, void>
    >>
>;
0 голосов
/ 30 августа 2018

Лично я чувствую, что самый ясный подход здесь - "управляемый данными". Поместить критерии в таблицу (написанную как специализации шаблона класса) и позволить компилятору выполнить сопоставление с образцом, чтобы определить тип короче, меньше подвержен ошибкам и легче читается или расширяется.

template<bool is_signed, std::size_t has_sizeof>
struct find_int_type_impl { using type = void; }; // Default case

template<> struct find_int_type_impl<true,  4> { using type = std::int32_t;  };
template<> struct find_int_type_impl<true,  8> { using type = std::int64_t;  };
template<> struct find_int_type_impl<false, 4> { using type = std::uint32_t; };
template<> struct find_int_type_impl<false, 8> { using type = std::uint64_t; };

template<bool is_signed, std::size_t has_sizeof>
using find_int_type = typename find_int_type_impl<is_signed, has_sizeof>::type;
...