Динамический массив переменных размеров в переполнении стека

Я хотел бы реализовать STL-подобный тензорный шаблон в C ++, которому нужен оператор перегрузки [] для доступа к его элементам, который может выглядеть следующим образом:

Tensor<double,2> tensor2
{
{1,2,3},
{4,5,6}
};
std::cout<< tensor2[1][2]<<'\n';

Для небольших размеров может быть легко использовать что-то вроде

std::vector<std::vector<int>>

Но это не будет легко использовать для более высоких размеров.
Также я хотел бы реализовать произведение между тензорами и сжатие между измерениями в одном тензоре.

0

Решение

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

namespace DataStructures
{
struct ExtentList   //Discribe extents of dimensions for MultiArray
{
std::vector<size_t> dimensions;
ExtentList() = default;
template<typename Iterator, typename SFINAE = std::enable_if_t<std::_Is_iterator_v<Iterator>>>
ExtentList(Iterator begin, Iterator end) : dimensions(begin, end) {}
//operator[] used to initialize the extents
ExtentList& operator[](size_t n) { dimensions.push_back(n); return *this; }
ExtentList after_front() const { return ExtentList(++dimensions.cbegin(), dimensions.cend()); }
//at() used to access extents
size_t at(size_t n) const { return dimensions.at(n); }
};

static ExtentList Extents;

template<
typename ElemType,                                                  //Underlying Type
size_t Dimension,                                                   //Dimension of MultiArray
typename ElementAllocator = std::allocator<ElemType>,               //Allocator for elements
template<typename, typename> typename ContainerType = std::vector,  //Underlying container type
template<typename> typename ContainerAllocator = std::allocator>    //Allocator for container
class MultiArray
{
//Necessary for contructor with ExtentList
friend class MultiArray<ElemType, Dimension + 1U, ElementAllocator, ContainerType, ContainerAllocator>;

using value_type = typename
std::conditional_t<
Dimension == 1U,
ElemType,
MultiArray<ElemType, Dimension - 1U, ElementAllocator, ContainerType, ContainerAllocator>>;
using allocator_type = typename
std::conditional_t<
Dimension == 1U,
ElementAllocator,
ContainerAllocator<value_type>>;
ContainerType<value_type, allocator_type> data;public:
MultiArray() = default;
MultiArray(size_t n, const value_type& val) : data(n, val) {}

template<typename SFINAE = std::enable_if_t<(Dimension == 1U)>>
MultiArray(ExtentList extents, const ElemType& elem) : data(extents.at(0), elem) {}
template<typename SFINAE = std::enable_if_t<(Dimension >= 2U)>, typename SFINAE2 = SFINAE>
MultiArray(ExtentList extents, const ElemType& elem) : data(extents.at(0), value_type(extents.after_front(), elem)) {}

MultiArray(std::initializer_list<value_type> ilist) : data(ilist) {}template<typename ... SizeType>
MultiArray(size_t N, SizeType... args) : data(N, value_type(args...)) {}

value_type& operator[](size_t n) { return data[n]; }
void push_back(const value_type& elem) { data.push_back(elem); }
};
}

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

namespace DS = DataStructures;

DS::MultiArray<int, 2> matrix_2d
{
{ 1,2,3 },
{ 4,5,6 },
{ 7,8,9 }
};
for (size_t i = 0; i != 3; ++i)
for (size_t j = 0; j != 3; ++j)
std::cout << matrix_2d[i][j] << ' ';

DS::MultiArray<int, 3> matrix_3d(DS::Extents[10][10][10], 0);
size_t sum = 0;
for (size_t i = 0; i != DS::Extents.at(0); ++i)
for (size_t j = 0; j != DS::Extents.at(1); ++j)
for (size_t k = 0; k != DS::Extents.at(2); ++k)
sum += (matrix_3d[i][j][k] = i * 100 + j * 10 + k);
std::cout << sum << '\n' << matrix_3d[9][9][9] << '\n';

Идея ExtentList исходит от Boost. Это лучше, чем список параметров переменной функции или шаблон переменной.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]