Тип шаблона C ++ с динамическим выделением - PullRequest
0 голосов
/ 07 июня 2018

Я ищу конструкцию, которая позволяет компилятору выбирать минимальный тип данных для данного целого числа в параметре шаблона.Проблема, по которой я не смог найти решение самостоятельно, заключается в том, как я хочу его использовать:

template<typename T, min_type<max_elements_to_store> max_elements_to_store>
class testClass {
private:
    T data[max_elements_to_store];
    min_type<max_elements_to_store> currently_selected_element;
};

Макрос "min_type" должен динамически выбирать тип с минимальным количеством битов для данного max_elements_to_store (uint8_t, uint16_t, uint32_t, uint64_t).Я мог бы исправить это, просто заменив min_type <> данным типом данных, но этот тип данных часто не был бы наилучшим выбором.Например,

template<typename T, uint64_t max_elements_to_store>
class testClass {
private:
    T data[max_elements_to_store];
    uint64_t currently_selected_element;
};

TestClass<uint8_t, 12> testObject;

Здесь массив будет содержать только 12 элементов, а переменная current_selected_element тратит много битов, которые просто не нужны для доступа только к 12 элементам.Кажется, это только небольшая проблема, но она ухудшается для многих переменных для доступа к данным в классе ...

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

Заранее спасибо!Inspire

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Вот альтернативное решение, использующее функции constexpr для индексации в кортеж параметров типа.

#include <iostream>
#include <tuple>

template <size_t size>
struct min_type {

    constexpr static inline size_t log2(size_t n)  {
        return ( (n<2) ? 0 : 1+log2(n/2));
    }

    constexpr static inline size_t get_index(size_t last,size_t value) {
        return value == 8 ?  last : get_index(last+1,value/2);
    }

    constexpr static inline std::size_t min_type_size(std::size_t v) {
        v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; 
        v |= v >> 8; v |= v >> 16; v++;
        return v < 8 ? 8 : v;
    }

    using type_options = std::tuple<uint8_t,uint16_t,uint32_t,uint64_t>;

    using type = typename std::tuple_element<
        get_index(0,min_type_size(log2(size))),
        type_options>::type;
};

template<typename T, size_t max_elements_to_store>
class testClass {
//private:
  public:
    T data[max_elements_to_store];
    typename min_type<max_elements_to_store>::type currently_selected_element;
};

int main()
{
    min_type<0xff>::type uint_8_value;
    min_type<0xffff>::type uint_16_value;
    min_type<0xffffffff>::type uint_32_value;
    min_type<0xffffffffffffffff>::type uint_64_value;

    static_assert(std::is_same< decltype(uint_8_value),uint8_t>::value,"...");
    static_assert(std::is_same< decltype(uint_16_value),uint16_t>::value,"...");
    static_assert(std::is_same< decltype(uint_32_value),uint32_t>::value,"...");
    static_assert(std::is_same< decltype(uint_64_value),uint64_t>::value,"...");

    testClass<int,12> testcls;

    static_assert(std::is_same< decltype(testcls.currently_selected_element),uint8_t>::value,"...");

    return 0;
}

Demo

0 голосов
/ 07 июня 2018

Один из способов сделать это - использовать std::conditional:

#include <type_traits>
#include <cstdint>
#include <limits>

template<std::size_t Count>
using min_type = std::conditional_t<Count <= std::numeric_limits<uint8_t>::max(), uint8_t,
                    std::conditional_t<Count <= std::numeric_limits<uint16_t>::max(), uint16_t,
                        std::conditional_t<Count <= std::numeric_limits<uint32_t>::max(), uint32_t,
                            std::conditional_t<Count <= std::numeric_limits<uint64_t>::max(), uint64_t, void>>>>;

// test: all of the following pass            
static_assert(std::is_same_v<min_type<12>, uint8_t>);
static_assert(std::is_same_v<min_type<1024>, uint16_t>);
static_assert(std::is_same_v<min_type<70000>, uint32_t>);
static_assert(std::is_same_v<min_type<5000000000>, uint64_t>);

template<typename T, std::size_t max_elements_to_store>
class testClass {
private:
    T data[max_elements_to_store];
    min_type<max_elements_to_store> currently_selected_element;
};

TestClass<uint8_t, 12> testObject;

Примечание: как отметил @ François Andrieux в комментариях, это не сэкономит память из-за заполнения (если вы не используетеспецифичное для компилятора расширение для принудительного создания упакованного представления класса).

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