#include <iostream>
#include <memory>

class Matrix {
private:
  int row;
  int column;
  std::shared_ptr<double> content;
public:

  Matrix() : row(0), column(0), content(nullptr) {}

  template<class... A> void set(int row, int column, A... args) {
    double *array_content = new double[row * column];
    double *p = array_content;
    int n = 0;
    for (double x : std::initializer_list<double>{args...}) {
      *p = x;
      p++; n++;
    }
    while (n < row * column) {
      *p = 0.0;
      p++; n++;
    }
    this->content.reset(array_content);
    this->row = row;
    this->column = column;
  }
  
  friend std::ostream &operator<<(std::ostream &os, Matrix &m) {
    for (int r = 0; r < m.row; r++) {
      for (int c = 0; c < m.column; c++) {
        os << *(m.content.get() + r * m.column + c) << " ";
      }
      if (r < m.row - 1) os << std::endl;
    }
    return os;
  }

  friend Matrix operator*(Matrix &a, Matrix &b) {
    Matrix m;
    if (a.column != b.row)
      return m;
    m.row = a.row;
    m.column = b.column;
    double *array_content = new double[m.row * m.column];
    for (int r = 0; r < m.row; r++) {
      for (int c = 0; c < m.column; c++) {
        double s = 0.0;
        for (int k = 0; k < a.column; k++)
          s += (*(a.content.get() + r * a.column + k) * *(b.content.get() + k * b.column + c));
        *(array_content + r * m.column + c) = s;
      }
    }
    m.content.reset(array_content);
    return m;
  }


  ~Matrix() {}
};

int main() {
  Matrix a, b, m;
  a.set(2, 2,  1.0, -2.0, 2.0,  3.0);
  b.set(2, 2, -2.0,  1.0, 3.0, -1.0);
  
  std::cout << a << std::endl;
  std::cout << "-------------------------" << std::endl;
  std::cout << b << std::endl;
  std::cout << "-------------------------" << std::endl;

  m = a * b;

  std::cout << m << std::endl;
  std::cout << "-------------------------" << std::endl;
  
  m = b * a;

  std::cout << m << std::endl;
  std::cout << "-------------------------" << std::endl;

  return 0;
}
/* end */
