Как эффективно развертывать последовательность с использованием шаблонов С++
У меня сложный тип C
в зависимости от параметра шаблона, который мне нужен в последовательности с ограничением длины. Функция constexpr next()
доступна для перехода от C_n → C_n + 1. Поскольку каждый элемент последовательности имеет другой тип, я использую std::tuple
для хранения результатов. Функции mkTuple()
заботятся о свитке (ограничено) последовательности.
Вот упрощенный пример того, что я сделал (используя std::array
в качестве заполнителя для моего более сложного C):
#include <array>
#include <tuple>
#include <iostream>
template<std::size_t OFFSET>
using C=std::array<uint8_t, OFFSET>;
static
constexpr
std::size_t
next(const std::size_t START, const std::size_t DISTANCE)
{
return START + DISTANCE;
}
template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE, std::size_t SEQ_LENGTH>
struct mkTuple
{
using _LT = CONTENT<START>;
using _RT = typename mkTuple<CONTENT, next(START, DISTANCE), DISTANCE, SEQ_LENGTH - 1>::tuple;
using tuple=decltype(std::tuple_cat(std::make_tuple(_LT()), _RT()));
};
template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE>
struct mkTuple<CONTENT, START, DISTANCE, 1>
{
using _LT = CONTENT<START>;
using tuple = std::tuple<_LT>;
};
int
main()
{
using tMyTuple = typename mkTuple<C, 16, 2, 64>::tuple;
const std::size_t iTupleLength = std::tuple_size<tMyTuple>::value;
std::cout << "Sequence length = " << iTupleLength << std::endl;
const tMyTuple myTuple;
std::cout << "Tuple[4].size() = " << std::get<4>(myTuple).size() << std::endl;
return 0;
}
Проблема в том, что мои функции mkTuple()
кажутся дорогостоящими soo-памятью, и я быстро сталкиваюсь с проблемой компилятора из памяти. Фактически g++ -ftime-report ...
сообщает > использование 1 ГБ для экземпляров шаблонов. И это число быстро (экспоненциально?) Возрастает с ростом длины последовательности.
Я подозреваю, что создание std::tuple
, требуемое для std::tuple_cat
, является надувным. У кого-нибудь есть хорошая идея, как повысить эффективность последовательности?
спасибо заранее!
Ответы
Ответ 1
Кажется, что std::tuple
является излишним для вашего сценария - вы можете работать только на уровне системной системы, а затем конвертировать в std::tuple
в конце.
Так как реализация std::tuple
большая и сложная, неудивительно, что она будет медленной для большого количества экземпляров. Создайте собственный typelist
:
template <typename... Ts>
struct typelist
{
using as_tuple = std::tuple<Ts...>;
};
template <typename... As, typename... Bs>
constexpr auto typelist_cat(typelist<As...>, typelist<Bs...>)
-> typelist<As..., Bs...>
{
return {};
}
Затем замените использование std::tuple
:
template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE, std::size_t SEQ_LENGTH>
struct mkTuple
{
using _LT = CONTENT<START>;
using _RT = typename mkTuple<CONTENT, START + DISTANCE, DISTANCE, SEQ_LENGTH - 1>::tuple;
using tuple = decltype(typelist_cat(typelist<_LT>{}, _RT{}));
};
template<template<std::size_t OFFSET> class CONTENT, std::size_t START, std::size_t DISTANCE>
struct mkTuple<CONTENT, START, DISTANCE, 1>
{
using _LT = CONTENT<START>;
using tuple = typelist<_LT>;
};
Наконец, конвертировать в конец:
using tMyTuple = typename mkTuple<C, 16, 2, 64>::tuple::as_tuple;
пример live wandbox
Вывод:
Длина последовательности = 64
Tuple [4].size() = 24