Создание во время компиляции массива шаблонных объектов в синтезе высокого уровня - PullRequest
0 голосов
/ 12 ноября 2018

Я пытаюсь сделать это с помощью HLS, а не с «нормальным» C ++, поэтому большинство библиотек (STL, boost и т. Д.) Не будут работать, поскольку их невозможно синтезировать (ручное управление памятью не допускается) , Я думаю, что это должно быть возможно с метапрограммированием шаблона, но я немного застрял.

Я хочу создать массив регистров сдвига, каждый с переменной глубиной. У меня есть N входов, и я хочу создать N сдвиговых регистров с глубиной от 1 до N, где N известно во время компиляции. Мой класс регистра сдвига в основном выглядит как

template<int DEPTH>
class shift_register{
    int registers[DEPTH];
    ...
};

Я попытался следовать этому и адаптировать его: Программно создавать статические массивы во время компиляции в C ++ , однако проблема заключается в последней строке. Каждый шаблонный сдвиговый регистр будет другого типа, и поэтому его нельзя будет собрать в массив. Но мне нужен массив, так как не было бы способа получить доступ к каждому регистру сдвига.

Любая помощь будет оценена!

Ответы [ 3 ]

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

Ваш вопрос было довольно сложно понять, но я сделаю все возможное ...

template <typename ... Args>
constexpr auto make_array(Args && ... pArgs)
{
    using type = std::common_type_t<std::decay_t<Args>...>;
    return std::array<type, sizeof...(Args)>{ (type)pArgs ... };
}

Тогда используйте это так:

auto constexpr var_array_of_arrays = std::make_tuple
(
    make_array(1, 2, 3, 3),
    make_array(2, 3, 4),
    make_array(1, 2, 3 ,4 ,3, 5)
);

Чтобы получить M-й элемент, к которому вы обращаетесь, он должен быть константой времени компиляции:

std::get<M>(var_array_of_arrays);

Чтобы получить доступ к N-му элементу в массиве Mth:

auto constexpr value = std::get<M>(var_array_of_arrays)[N]

Для улучшения интерфейса:

template <size_t M, size_t N, typename T >
constexpr decltype(auto) get_element(T && pInput)
{
    return std::get<M>(std::forward<T>(pInput))[N];
}

Используется так:

auto constexpr element0_1 = get_element<0, 1>(var_array_of_arrays);

Это позволит вам использовать массив массивов переменной длины или, по крайней мере, что-то, что ведет себя так же и идентично тому, что в памяти. Полный пример здесь: Онлайн-компилятор

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

Всякий раз, когда я слышу «последовательность чисел времени компиляции», я думаю std::index_sequence

namespace detail {
    template <typename>
    struct shift_registers;

    template <std::size_t ... Is> // 0, 1, ... N-1
    struct shift_registers<std::index_sequence<Is...> > {
        using type = std::tuple<shift_register<Is + 1>...>;
    };

    template <typename T>
    using shift_registers_t = typename shift_registers<T>::type
}

template <std::size_t N>
using shift_registers = detail::shift_registers_t<std::make_index_sequence<N>>;
0 голосов
/ 12 ноября 2018

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

Например, если бы у меня было N = 4, я мог бы легко написать это как:

shift_register<1> sr1;
shift_register<2> sr2;
shift_register<3> sr3;
shift_register<4> sr4;

Но это было бы нелегко изменить, если бы я хотел другое значение для Nв будущем.

В итоге я использовал препроцессор и нашел решение: Как мне написать рекурсивный макрос "repeat" для цикла for для генерации кода C с препроцессором CPP?

Я использовал макросы из этого решения следующим образом:

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

#define BODY(i) shift_register<i> CAT(sr,i) 
REPEAT_ADD_ONE(BODY, N, 1);

А затем нечто подобное для доступа к регистрам сдвига в виде массива.

Это позволило мне добиться генерации времени компиляции, которую я искал, и получить доступ к типу массива, который мне был нужен.

...