Если у вас есть фиксированный размер во время компиляции, но вы хотите использовать динамическое распределение, вы можете либо выбрать тип распределения («стек»/«куча») каждого объекта отдельно, либо построить динамическое распределение в Matrix
класс.
Пример динамического распределения за пределами класса Matrix
. Обратите внимание, что использование списков инициализаторов не позволяет проверять во время компиляции количество элементов, переданных на ctor, в (за исключением объявления contexpr
экземпляров Matrix
). Поэтому я представил довольно глупые дополнения, чтобы продемонстрировать проверки размера компиляции.
#include <memory>
#include <iostream>
#include <array>
template < typename T, std::size_t rows, std::size_t columns >
struct Matrix
{
public:
Matrix(std::initializer_list<T> p)
{
if(p.size() != rows*columns) { /* throw */ }
std::copy(p.begin(), p.end(), storage_member.begin());
}
Matrix(std::array<T, columns*rows> const& p)
{
std::copy(p.begin(), p.end(), storage_member.begin());
}
Matrix(std::initializer_list< std::initializer_list<T> > p)
{
if(p.size() != rows) { /* throw */ }
auto itRow = p.begin();
for(std::size_t row = 0; row < rows; ++row, ++itRow)
{
if(itRow->size() != columns) { /* throw */ }
auto itCol = itRow->begin();
for(std::size_t col = 0; col < columns; ++col, ++itCol)
{
storage_member[col+row*columns] = *itCol;
}
}
}
Matrix(std::array<std::array<T, columns>, rows> const& p)
{
for(std::size_t row = 0; row < rows; ++row)
{
for(std::size_t col = 0; col < columns; ++col)
{
storage_member[col+row*columns] = p[row][col];
}
}
}
// getters, setters
T& operator() (std::size_t row, std::size_t col)
{
return storage_member[col+row*columns];
}
private:
// storage, e.g.
std::array<T, columns*rows> storage_member;
};
template < typename T, typename... TP>
constexpr std::array<T,sizeof...(TP)+1> m(T&& p, TP... pp)
{
return {{p, pp...}};
}
// usage:
int main()
{
using My_Matrix_Type = Matrix < int, 2, 2 >;
std::unique_ptr <My_Matrix_Type> pmyMatrix0{ new My_Matrix_Type({1,2,3,4}) };
std::unique_ptr <My_Matrix_Type> pmyMatrix1{ new My_Matrix_Type({{1,2},{3,4}}) };
// with compile-time size checks
std::unique_ptr <My_Matrix_Type> pmyMatrix2{ new My_Matrix_Type(m(1,2,3,4)) };
std::unique_ptr <My_Matrix_Type> pmyMatrix3{ new My_Matrix_Type(m(m(1,2), m(3,4))) };
// a more fancy but possible syntax, would require some additional effort:
//std::unique_ptr <My_Matrix_Type> pmyMatrix4{ new My_Matrix_Type(b(1,2)(3,4)) };
std::cout << (*pmyMatrix0)(1,1) << std::endl;
std::cout << (*pmyMatrix1)(1,1) << std::endl;
std::cout << (*pmyMatrix2)(1,1) << std::endl;
std::cout << (*pmyMatrix3)(1,1) << std::endl;
}
В приведенном выше примере, вы можете сразу же заменить storage_member
на динамически выделенный массив, чтобы динамическое распределение встроенный.
Если вы не знаете размер во время компиляции, вы должны были построить динамическое распределение в Matrix
класса (как упоминалось выше). Поскольку вы можете вывести размер (столбцы, строки) двухуровневых списков инициализаторов, вам нужно было только удалить ctors с использованием массивов фиксированного размера и изменить ctor с 1-разрядными списками инициализаторов, например:
template < typename T > // no size parameters!
struct Matrix
{
Matrix(std::size_t columns, std::size_t rows, std::initializer_list<T> p);
Matrix(std::initializer_list< std::initializer_list<T> > p);
// maybe an additional ctor for dynamically allocated arrays
// getters, setters, data members
};
// usage:
Matrix myMatrix0(2, 2, {1,2,3,4});
Matrix myMatrix1({{1,2},{3,4}});
Конечно, вы можете написать конструктор, который принимает 'std :: initializer_list'. –
@KerrekSB: Вы уверены? AFAICT это невозможно ([live example] (http://liveworkspace.org/code/3kW04t$309)) –
Вы чертовски настроены по этому синтаксису или будете немного отличаться от призыва? – delnan