Today I started learning C++ and at the end of the day have made a simple generic matrix class. I'm looking for feedback on techniques and features. It's still not complete, though. But everything works!
I put some functions outside the class and inside a namespace because I was trouble defining template member functions with partial specialization.
Matrix.hpp
#pragma once
#include <iostream>
template <typename T, int m, int n = m>
class mat {
template <typename, int, int>
friend class mat;
private:
T * data;
public:
mat(const std::initializer_list<T> & ini) {
std::copy(ini.begin(), ini.end(), data);
}
mat() : data(new T[m * n]) {
}
mat(T * values) : data(values) {
}
mat(const mat & mat2) : mat(){
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
data[i * n + j] = mat2(i, j);
}
~mat() {
delete data;
}
void fill(T val) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
data[i * n + j] = val;
}
void print() {
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j)
std::cout << data[i * n + j] << " ";
std::cout << std::endl;
}
}
mat<T, m, 1> col(int j) const {
mat<T, m, 1> col;
for (int i = 0; i < m; ++i)
col.data[i] = data[i * n + j];
return col;
}
mat<T, 1, n> row(int i) const {
mat<T, 1, n> row;
std::copy_n(data + i * n, n, row.data);
return row;
}
T operator () (int row, int col) const {
return data[row * n + col];
}
T & operator () (int row, int col) {
return data[row * n + col];
}
mat<T, n, m> transpose() const {
mat<T, n, m> res;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
res(j, i) = this->data[i * n + j];
return res;
}
template <int p>
mat<T, m, p> operator * (const mat<T, n, p> & other) const {
mat<T, m, p> res;
for (int i = 0; i < m; ++i)
for (int j = 0; j < p; ++j) {
T sum = 0;
for (int k = 0; k < n; ++k)
sum += this->data[i * n + k] * other.data[k * n + j];
res(i, j) = sum;
}
return res;
}
mat<T, m, n> & operator *= (T val) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
data[i * n + j] *= val;
return *this;
}
mat<T, m, n> & operator /= (T val) {
return this *= 1 / val;
}
mat<T, m, n> & operator += (const mat & other) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
data[i * n + j] += other(i, j);
return *this;
}
mat<T, m, n> & operator -= (const mat & other) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
data[i * n + j] -= other(i, j);
return *this;
}
mat<T, m, n> operator * (T val) const {
auto res(*this);
res *= val;
return res;
}
mat<T, m, n> operator / (T val) const {
return (*this) * (1 / val);
}
mat<T, m, n> operator + (const mat & other) const {
auto res(*this);
res += other;
return res;
}
mat<T, m, n> operator - (const mat & other) const {
auto res(*this);
res -= other;
return res;
}
mat<T, m - 1, n - 1> cut(int row, int col) const {
mat<T, m - 1, n - 1> res;
int index = 0;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j) {
if (i == row || j == col)
continue;
res.data[index++] = data[i * n + j];
}
return res;
}
};
namespace matrix {
template <typename T>
T det(const mat<T, 1, 1> & arg) {
return arg(0, 0);
}
template <typename T>
T det(const mat<T, 2, 2> & arg) {
return arg(0, 0) * arg(1, 1) - arg(1, 0) * arg(0, 1);
}
template <typename T, int n>
T det(const mat<T, n, n> & arg) {
T res = 0, coef = 1;
for (int i = 0; i < n; ++i, coef *= -1) {
res += coef * arg(0, i) * matrix::det(arg.cut(0, i));
}
return res;
}
template <typename T>
mat<T, 2, 2> inv(const mat<T, 2, 2> & arg) {
mat<T, 2, 2> helper;
helper(1, 1) = arg(0, 0);
helper(0, 0) = arg(1, 1);
helper(0, 1) = -arg(0, 1);
helper(1, 0) = -arg(1, 0);
return helper / det(arg);
}
template <typename T, int m>
mat<T, m, m> id() {
mat<T, m, m> res;
for (int i = 0; i < m; ++i)
res(i, i) = 1;
return res;
}
};
Main.cpp
#include <iostream>
#include <exception>
#include "Matrix.hpp"
using namespace std;
int main() {
constexpr int size = 4;
long * data = new long[size * size]{ 0 };
for (int i = 0; i < size; ++i)
data[size * i + i] = 2;
mat<long, size> big(data);
cout << matrix::det(big) << endl;
return 0;
}