Нужно создать массив с элементами у которых разный размер. Размер массива, элементов, и их порядок известен в compile-time. В коде могу представить так:
template<int N = 5>
struct A {
std::array<int, N> = {
// Вот эти значения должны как то создаваться автоматически
// 1...N, N = 5
std::array<int, 1>,
std::array<int, 2>,
std::array<int, 3>,
std::array<int, 4>,
std::array<int, 5>,
};
};
template<int N = 3>
struct B {
std::array<int, N> = {
// Вот эти значения должны как то создаваться автоматически
std::array<int, 1>,
std::array<int, 2>,
std::array<int, 3>,
};
};
Есть что то готовое, что можно использовать, и работающее в компилтайме?
-----------------------------------------------------
Первое решение:
#include <type_traits>
#include <iostream>
#include <tuple>
#include <array>
template <typename... Ts>
class tuple_array_t : public std::tuple<Ts...> {
public:
using std::tuple<Ts...>::tuple;
template <size_t N>
constexpr auto&& operator[](std::integral_constant<size_t, N>) {
return std::get<N>(*this);
}
[[nodiscard]] constexpr auto size() const {
return std::integral_constant<std::size_t, std::tuple_size_v<decltype(static_cast<std::tuple<Ts...>>(*this))>>();
}
};
template <std::size_t From, std::size_t To, class F>
constexpr void constexpr_for_range(F&& f) {
if constexpr (From < To) {
f(std::integral_constant<size_t, From>());
constexpr_for_range<(std::size_t)From + 1, (std::size_t)To>(f);
}
}
template<typename T, size_t N, typename... Ts>
constexpr auto linear_tuple_array() {
if constexpr (N > 1) {
return linear_tuple_array<T, N - 1, Ts..., std::array<T, N>>();
} else {
return tuple_array_t<Ts..., std::array<T, N>>();
}
}
constexpr auto generate_super_array() {
auto linear_array = linear_tuple_array<float, 10>();
auto linear_array_size = linear_array.size();
constexpr_for_range<0, linear_array.size()>([&] (auto i) {
constexpr auto n = linear_array_size - i;
constexpr_for_range<0, n>([&] (auto j) {
linear_array[i][j] = i * 1000 + j;
});
});
return linear_array;
}
int main() {
auto array = generate_super_array();
auto x = std::integral_constant<std::size_t, 5>();
auto y = std::integral_constant<std::size_t, 3>();
// #output: 5003
std::cout << array[x][y] << std::endl;
}
------------------------------------------------
Второе решение
#include <cstddef>
#include <type_traits>
#include <iostream>
template <typename T, size_t N>
class ctmat;
template <typename T>
class ctmat<T, 1>
{
public:
template <size_t i, size_t j>
typename std::enable_if<i == 0 && j == 0, T>::type& get() { return m_v[0]; }
template <size_t i, size_t j>
typename std::enable_if<i == 0 && j == 0, T>::type const& get() const { return m_v[0]; }
template <typename U>
friend std::ostream& operator<<(std::ostream& out, const ctmat<U, 1>& m);
private:
T m_v[1];
};
template <typename T, size_t N>
class ctmat: public ctmat<T, N-1>
{
public:
typedef ctmat<T, N-1> base_type;
using base_type::get;
template <size_t i, size_t j>
typename std::enable_if<i == N-1 && j < N, T>::type& get() { return m_v[j]; }
template <size_t i, size_t j>
typename std::enable_if<i == N-1 && j < N, T>::type const& get() const { return m_v[j]; }
base_type& base() { return static_cast<base_type>(*this); }
base_type const& base() const { return static_cast<const base_type&>(*this); }
template <typename U, size_t M>
friend std::ostream& operator<<(std::ostream& out, const ctmat<U, M>& m);
private:
T m_v[N];
};
template <typename T>
std::ostream& operator<<(std::ostream& out, const ctmat<T,1>& m)
{
out << m.m_v[0] << std::endl;
return out;
}
template <typename T, size_t N>
std::ostream& operator<<(std::ostream& out, const ctmat<T, N>& m)
{
out << m.base();
for (size_t j = 0; j != N; ++j)
out << m.m_v[j] << ' ';
out << std::endl;
return out;
}
int main()
{
ctmat<int, 1> m1;
static_assert(sizeof(m1) == sizeof(int), "Unexpected size");
m1.get<0,0>() = 1;
//m1.get<1,0>() = 2;
//m1.get<0,1>() = 3;
std::cout << m1;
ctmat<int, 2> m2;
static_assert(sizeof(m2) == 3*sizeof(int), "Unexpected size");
m2.get<0,0>() = 4;
//m2.get<0,1>() = 5;
m2.get<1,0>() = 6;
m2.get<1,1>() = 7;
std::cout << m2;
return 0;
}