Simple Matrix Template Class












0














I wanted to make a matrix template class to see if I can learn how to use templates, work on figuring out the indexing in loops, and making an interface so the user can know if an operation will work. Eventually I would like to add more cache optimization, calculating the inverse, and other ways to get data into the matrix such as raw pointers.



For now everything is one header and I will separate out the implementation



#pragma once
#include <cstdint>
#include <vector>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <functional>
#include <type_traits>

template<typename T>
class LiteMatrix
{
public:
LiteMatrix(const size_t &rows, const size_t &cols);
LiteMatrix(const size_t &rows, const size_t &cols, const std::vector<T>&data);
~LiteMatrix() = default;

LiteMatrix(const LiteMatrix &rhs) = default; // copy constructor
LiteMatrix(LiteMatrix && rhs) = default; // move constructor

LiteMatrix& operator=(const LiteMatrix& rhs) = default; // copy assignment
LiteMatrix& operator=(LiteMatrix&& rhs) = default; // move assignment

LiteMatrix& zeroes();
LiteMatrix& ones();

LiteMatrix operator+(const LiteMatrix<T> &rhs);
LiteMatrix& operator+=(const LiteMatrix<T>& rhs);
LiteMatrix operator-(const LiteMatrix<T> &rhs);
LiteMatrix& operator-=(const LiteMatrix<T>& rhs);
LiteMatrix operator*(const LiteMatrix<T> &rhs);
LiteMatrix& operator*=(const LiteMatrix<T>& rhs);
T& operator()(const size_t &rIndex, const size_t &cIndex);

LiteMatrix operator*(const T &rhs);
LiteMatrix& operator*=(const T &rhs);

bool operator!=(const LiteMatrix<T>& rhs) const;
bool operator==(const LiteMatrix<T>& rhs) const;

template<typename T>
friend std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs);

size_t rowCount() const;
size_t colCount() const;

bool isAddSubLegal(const LiteMatrix& rhs) const;
bool isMultLegal(const LiteMatrix& rhs) const;

void setMatrix(const std::vector<T>& val);
void setElement(const size_t row, const size_t col, const T& val);
void setRow(const size_t row, const std::vector<T> val);
void setCol(const size_t col, const std::vector<T> val);
T getElement(const size_t row, const size_t col) const;

LiteMatrix& transpose();

private:
size_t m_rows;
size_t m_cols;

std::vector<T> m_mat;
};

//#include "LiteMatrix.tcc"

template<typename T>
LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols)
: m_rows(rows), m_cols(cols)
{
m_mat = std::vector<T>(rows * cols);
}

template<typename T>
LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols, const std::vector<T>& data)
: m_rows(rows), m_cols(cols), m_mat(data)
{
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::zeroes()
{
std::fill(m_mat.begin(), m_mat.end(), 0);

return *this;
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::ones()
{
std::fill(m_mat.begin(), m_mat.end(), 1);

return *this;
}

template<typename T>
LiteMatrix<T> LiteMatrix<T>::operator+(const LiteMatrix& rhs)
{
LiteMatrix ret(*this);
ret += rhs;
return ret;
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::operator+=(const LiteMatrix& rhs)
{
if (!isAddSubLegal(rhs))
throw std::range_error("Matrix sizes are not compatiblen");

std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
m_mat.begin(), std::plus<>());

return *this;
}

template<typename T>
LiteMatrix<T> LiteMatrix<T>::operator-(const LiteMatrix& rhs)
{
LiteMatrix ret(*this);
ret -= rhs;
return ret;
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::operator-=(const LiteMatrix& rhs)
{
if (!isAddSubLegal(rhs))
throw std::range_error("Matrix sizes are not compatiblen");

std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
m_mat.begin(), std::minus<>());

return *this;
}

template<typename T>
LiteMatrix<T> LiteMatrix<T>::operator*(const LiteMatrix& rhs)
{
LiteMatrix ret(*this);
ret *= rhs;
return ret;
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::operator*=(const LiteMatrix& rhs)
{
if (!isMultLegal(rhs))
throw std::range_error("Matrix index are not compatiblen");

LiteMatrix<T> temp(m_rows, rhs.m_cols);

for (size_t i = 0; i < m_rows; i++)
{
for (size_t j = 0; j < m_cols; ++j)
{
for (size_t k = 0; k < m_cols; ++k)
{
temp.m_mat[i * rhs.m_cols + j] += m_mat[i * m_cols + k] * rhs.m_mat[j + k * m_cols];
}
}
}

*this = std::move(temp);

return *this;
}

template<typename T>
LiteMatrix<T> LiteMatrix<T>::operator*(const T& rhs)
{
LiteMatrix ret(*this);
ret *= rhs;
return ret;
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::operator*=(const T& rhs)
{
std::transform(m_mat.begin(), m_mat.end(), m_mat.begin(),
std::bind(std::multiplies<T>(), std::placeholders::_1, rhs));

return *this;
}

template<typename T>
T& LiteMatrix<T>::operator()(const size_t& rIndex, const size_t& cIndex)
{
return m_mat[rIndex * m_cols + cIndex];
}

template<typename T>
bool LiteMatrix<T>::operator!=(const LiteMatrix& rhs) const
{
bool isNotEqual = false;

for (size_t i = 0; i < m_rows; i++)
{
for (size_t j = 0; j < m_cols; ++j)
{
isNotEqual = std::numeric_limits<T>::epsilon() <=
std::abs(m_mat[i * m_cols + j] - rhs.m_mat[i * m_cols + j]);
if (isNotEqual)
break;
}
}
return isNotEqual;
}

template<typename T>
bool LiteMatrix<T>::operator==(const LiteMatrix& rhs) const
{
return !(*this != rhs);
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs)
{
for (size_t i = 0; i < rhs.m_rows; ++i)
{
for (size_t j = 0; j < rhs.m_cols; ++j)
os << std::setw(5) << std::setprecision(2) << rhs.m_mat[i * rhs.m_cols + j] << ' ';

os << 'n';
}
return os;
}

template<typename T>
size_t LiteMatrix<T>::rowCount() const
{
return m_rows;
}

template<typename T>
size_t LiteMatrix<T>::colCount() const
{
return m_cols;
}

template<typename T>
bool LiteMatrix<T>::isAddSubLegal(const LiteMatrix& rhs) const
{
return ((m_rows == rhs.m_rows) && (m_cols == rhs.m_cols));
}

template<typename T>
bool LiteMatrix<T>::isMultLegal(const LiteMatrix& rhs) const
{
return (m_cols == rhs.m_rows);
}

template<typename T>
void LiteMatrix<T>::setMatrix(const std::vector<T>& val)
{
std::copy(val.begin(), val.end(), m_mat.begin());
return;
}

template<typename T>
void LiteMatrix<T>::setElement(const size_t row, const size_t col, const T& val)
{
m_mat.at(row * m_rows + col) = val;
return;
}

template<typename T>
void LiteMatrix<T>::setRow(const size_t row, const std::vector<T> val)
{
if(row >= m_rows)
throw std::range_error("Matrix index is out of rangen");
if (val.size() > m_cols)
{
throw std::range_error("Data size is too largen");
}

std::copy(val.begin(), val.end(), m_mat.begin() + row * m_cols);
}

template<typename T>
void LiteMatrix<T>::setCol(const size_t col, const std::vector<T> val)
{
if (col >= m_cols)
throw std::range_error("Matrix index is out of rangen");
if (val.size() > m_rows)
{
throw std::range_error("Data size is too largen");
}

for (size_t i = 0; i != val.size(); i++)
{
m_mat[col + i * m_rows] = val[i];
}
}

template<typename T>
T LiteMatrix<T>::getElement(const size_t row, const size_t col) const
{
return m_mat.at(row * m_rows + col);
}

template<typename T>
LiteMatrix<T>& LiteMatrix<T>::transpose()
{
// TODO: insert return statement here
if (m_cols != 1 && m_rows != 1)
{
decltype(m_cols) colStart = 0;
for (size_t i = 0; i < m_rows; ++i)
{
for (size_t j = colStart; j < m_cols; ++j)
{
std::iter_swap(m_mat.begin() + (i * m_cols + j),
m_mat.begin() + (j * m_rows + i));
}
++colStart;
}
}

std::swap(m_rows, m_cols);

return *this;
}


main.cpp



#include "LiteMatrix.h"
#include <iostream>

int main()
{
LiteMatrix<double> m1(2, 2);
std::cout << "Row Count: " << m1.rowCount() << std::endl;
std::cout << "Column Count: " << m1.colCount() << std::endl;

LiteMatrix<double> m2(2, 2);
std::cout << m1.ones();
std::cout << m2.ones();

LiteMatrix<double> m4(2, 2, std::vector<double>{1, 2, 3, 4});
LiteMatrix<double> m5(2, 1);
m5.setMatrix(std::vector<double> {7.5, 10.8});

LiteMatrix<double> m6(3, 3, std::vector<double>{1, 2, 3, 4, 5, 6, 7, 8, 9});
std::cout << "m6n";
std::cout << m6;
std::cout << m6.transpose();

LiteMatrix<double> m7(3, 1, std::vector<double>{1, 2, 3});
std::cout << "m7n";
std::cout << m7;
std::cout << m7.transpose();

m1.setElement(0, 0, 19.0);
std::cout << m1.getElement(0, 0);

std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m2) << std::endl;

m1 += m1;
std::cout << "m1 + m2n" << m1 + m2;
std::cout << "m2 - m2n" << m2 - m2;
std::cout << "m1 * m2n" << m1 * m2;

std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

m1.ones();

std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

LiteMatrix<double> m3(10, 10);
m3.ones();

std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m3) << std::endl;

m3.setRow(0, std::vector<double> {22, 33, 44, 55});
m3.setCol(9, std::vector<double> {66, 77, 88, 99});
std::cout << m3;
if(m1.isAddSubLegal(m3))
m3 += m1;

return 0;
}









share|improve this question







New contributor




Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    0














    I wanted to make a matrix template class to see if I can learn how to use templates, work on figuring out the indexing in loops, and making an interface so the user can know if an operation will work. Eventually I would like to add more cache optimization, calculating the inverse, and other ways to get data into the matrix such as raw pointers.



    For now everything is one header and I will separate out the implementation



    #pragma once
    #include <cstdint>
    #include <vector>
    #include <iostream>
    #include <iomanip>
    #include <algorithm>
    #include <functional>
    #include <type_traits>

    template<typename T>
    class LiteMatrix
    {
    public:
    LiteMatrix(const size_t &rows, const size_t &cols);
    LiteMatrix(const size_t &rows, const size_t &cols, const std::vector<T>&data);
    ~LiteMatrix() = default;

    LiteMatrix(const LiteMatrix &rhs) = default; // copy constructor
    LiteMatrix(LiteMatrix && rhs) = default; // move constructor

    LiteMatrix& operator=(const LiteMatrix& rhs) = default; // copy assignment
    LiteMatrix& operator=(LiteMatrix&& rhs) = default; // move assignment

    LiteMatrix& zeroes();
    LiteMatrix& ones();

    LiteMatrix operator+(const LiteMatrix<T> &rhs);
    LiteMatrix& operator+=(const LiteMatrix<T>& rhs);
    LiteMatrix operator-(const LiteMatrix<T> &rhs);
    LiteMatrix& operator-=(const LiteMatrix<T>& rhs);
    LiteMatrix operator*(const LiteMatrix<T> &rhs);
    LiteMatrix& operator*=(const LiteMatrix<T>& rhs);
    T& operator()(const size_t &rIndex, const size_t &cIndex);

    LiteMatrix operator*(const T &rhs);
    LiteMatrix& operator*=(const T &rhs);

    bool operator!=(const LiteMatrix<T>& rhs) const;
    bool operator==(const LiteMatrix<T>& rhs) const;

    template<typename T>
    friend std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs);

    size_t rowCount() const;
    size_t colCount() const;

    bool isAddSubLegal(const LiteMatrix& rhs) const;
    bool isMultLegal(const LiteMatrix& rhs) const;

    void setMatrix(const std::vector<T>& val);
    void setElement(const size_t row, const size_t col, const T& val);
    void setRow(const size_t row, const std::vector<T> val);
    void setCol(const size_t col, const std::vector<T> val);
    T getElement(const size_t row, const size_t col) const;

    LiteMatrix& transpose();

    private:
    size_t m_rows;
    size_t m_cols;

    std::vector<T> m_mat;
    };

    //#include "LiteMatrix.tcc"

    template<typename T>
    LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols)
    : m_rows(rows), m_cols(cols)
    {
    m_mat = std::vector<T>(rows * cols);
    }

    template<typename T>
    LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols, const std::vector<T>& data)
    : m_rows(rows), m_cols(cols), m_mat(data)
    {
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::zeroes()
    {
    std::fill(m_mat.begin(), m_mat.end(), 0);

    return *this;
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::ones()
    {
    std::fill(m_mat.begin(), m_mat.end(), 1);

    return *this;
    }

    template<typename T>
    LiteMatrix<T> LiteMatrix<T>::operator+(const LiteMatrix& rhs)
    {
    LiteMatrix ret(*this);
    ret += rhs;
    return ret;
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::operator+=(const LiteMatrix& rhs)
    {
    if (!isAddSubLegal(rhs))
    throw std::range_error("Matrix sizes are not compatiblen");

    std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
    m_mat.begin(), std::plus<>());

    return *this;
    }

    template<typename T>
    LiteMatrix<T> LiteMatrix<T>::operator-(const LiteMatrix& rhs)
    {
    LiteMatrix ret(*this);
    ret -= rhs;
    return ret;
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::operator-=(const LiteMatrix& rhs)
    {
    if (!isAddSubLegal(rhs))
    throw std::range_error("Matrix sizes are not compatiblen");

    std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
    m_mat.begin(), std::minus<>());

    return *this;
    }

    template<typename T>
    LiteMatrix<T> LiteMatrix<T>::operator*(const LiteMatrix& rhs)
    {
    LiteMatrix ret(*this);
    ret *= rhs;
    return ret;
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::operator*=(const LiteMatrix& rhs)
    {
    if (!isMultLegal(rhs))
    throw std::range_error("Matrix index are not compatiblen");

    LiteMatrix<T> temp(m_rows, rhs.m_cols);

    for (size_t i = 0; i < m_rows; i++)
    {
    for (size_t j = 0; j < m_cols; ++j)
    {
    for (size_t k = 0; k < m_cols; ++k)
    {
    temp.m_mat[i * rhs.m_cols + j] += m_mat[i * m_cols + k] * rhs.m_mat[j + k * m_cols];
    }
    }
    }

    *this = std::move(temp);

    return *this;
    }

    template<typename T>
    LiteMatrix<T> LiteMatrix<T>::operator*(const T& rhs)
    {
    LiteMatrix ret(*this);
    ret *= rhs;
    return ret;
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::operator*=(const T& rhs)
    {
    std::transform(m_mat.begin(), m_mat.end(), m_mat.begin(),
    std::bind(std::multiplies<T>(), std::placeholders::_1, rhs));

    return *this;
    }

    template<typename T>
    T& LiteMatrix<T>::operator()(const size_t& rIndex, const size_t& cIndex)
    {
    return m_mat[rIndex * m_cols + cIndex];
    }

    template<typename T>
    bool LiteMatrix<T>::operator!=(const LiteMatrix& rhs) const
    {
    bool isNotEqual = false;

    for (size_t i = 0; i < m_rows; i++)
    {
    for (size_t j = 0; j < m_cols; ++j)
    {
    isNotEqual = std::numeric_limits<T>::epsilon() <=
    std::abs(m_mat[i * m_cols + j] - rhs.m_mat[i * m_cols + j]);
    if (isNotEqual)
    break;
    }
    }
    return isNotEqual;
    }

    template<typename T>
    bool LiteMatrix<T>::operator==(const LiteMatrix& rhs) const
    {
    return !(*this != rhs);
    }

    template<typename T>
    std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs)
    {
    for (size_t i = 0; i < rhs.m_rows; ++i)
    {
    for (size_t j = 0; j < rhs.m_cols; ++j)
    os << std::setw(5) << std::setprecision(2) << rhs.m_mat[i * rhs.m_cols + j] << ' ';

    os << 'n';
    }
    return os;
    }

    template<typename T>
    size_t LiteMatrix<T>::rowCount() const
    {
    return m_rows;
    }

    template<typename T>
    size_t LiteMatrix<T>::colCount() const
    {
    return m_cols;
    }

    template<typename T>
    bool LiteMatrix<T>::isAddSubLegal(const LiteMatrix& rhs) const
    {
    return ((m_rows == rhs.m_rows) && (m_cols == rhs.m_cols));
    }

    template<typename T>
    bool LiteMatrix<T>::isMultLegal(const LiteMatrix& rhs) const
    {
    return (m_cols == rhs.m_rows);
    }

    template<typename T>
    void LiteMatrix<T>::setMatrix(const std::vector<T>& val)
    {
    std::copy(val.begin(), val.end(), m_mat.begin());
    return;
    }

    template<typename T>
    void LiteMatrix<T>::setElement(const size_t row, const size_t col, const T& val)
    {
    m_mat.at(row * m_rows + col) = val;
    return;
    }

    template<typename T>
    void LiteMatrix<T>::setRow(const size_t row, const std::vector<T> val)
    {
    if(row >= m_rows)
    throw std::range_error("Matrix index is out of rangen");
    if (val.size() > m_cols)
    {
    throw std::range_error("Data size is too largen");
    }

    std::copy(val.begin(), val.end(), m_mat.begin() + row * m_cols);
    }

    template<typename T>
    void LiteMatrix<T>::setCol(const size_t col, const std::vector<T> val)
    {
    if (col >= m_cols)
    throw std::range_error("Matrix index is out of rangen");
    if (val.size() > m_rows)
    {
    throw std::range_error("Data size is too largen");
    }

    for (size_t i = 0; i != val.size(); i++)
    {
    m_mat[col + i * m_rows] = val[i];
    }
    }

    template<typename T>
    T LiteMatrix<T>::getElement(const size_t row, const size_t col) const
    {
    return m_mat.at(row * m_rows + col);
    }

    template<typename T>
    LiteMatrix<T>& LiteMatrix<T>::transpose()
    {
    // TODO: insert return statement here
    if (m_cols != 1 && m_rows != 1)
    {
    decltype(m_cols) colStart = 0;
    for (size_t i = 0; i < m_rows; ++i)
    {
    for (size_t j = colStart; j < m_cols; ++j)
    {
    std::iter_swap(m_mat.begin() + (i * m_cols + j),
    m_mat.begin() + (j * m_rows + i));
    }
    ++colStart;
    }
    }

    std::swap(m_rows, m_cols);

    return *this;
    }


    main.cpp



    #include "LiteMatrix.h"
    #include <iostream>

    int main()
    {
    LiteMatrix<double> m1(2, 2);
    std::cout << "Row Count: " << m1.rowCount() << std::endl;
    std::cout << "Column Count: " << m1.colCount() << std::endl;

    LiteMatrix<double> m2(2, 2);
    std::cout << m1.ones();
    std::cout << m2.ones();

    LiteMatrix<double> m4(2, 2, std::vector<double>{1, 2, 3, 4});
    LiteMatrix<double> m5(2, 1);
    m5.setMatrix(std::vector<double> {7.5, 10.8});

    LiteMatrix<double> m6(3, 3, std::vector<double>{1, 2, 3, 4, 5, 6, 7, 8, 9});
    std::cout << "m6n";
    std::cout << m6;
    std::cout << m6.transpose();

    LiteMatrix<double> m7(3, 1, std::vector<double>{1, 2, 3});
    std::cout << "m7n";
    std::cout << m7;
    std::cout << m7.transpose();

    m1.setElement(0, 0, 19.0);
    std::cout << m1.getElement(0, 0);

    std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m2) << std::endl;

    m1 += m1;
    std::cout << "m1 + m2n" << m1 + m2;
    std::cout << "m2 - m2n" << m2 - m2;
    std::cout << "m1 * m2n" << m1 * m2;

    std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
    std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

    m1.ones();

    std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
    std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

    LiteMatrix<double> m3(10, 10);
    m3.ones();

    std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m3) << std::endl;

    m3.setRow(0, std::vector<double> {22, 33, 44, 55});
    m3.setCol(9, std::vector<double> {66, 77, 88, 99});
    std::cout << m3;
    if(m1.isAddSubLegal(m3))
    m3 += m1;

    return 0;
    }









    share|improve this question







    New contributor




    Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      0












      0








      0







      I wanted to make a matrix template class to see if I can learn how to use templates, work on figuring out the indexing in loops, and making an interface so the user can know if an operation will work. Eventually I would like to add more cache optimization, calculating the inverse, and other ways to get data into the matrix such as raw pointers.



      For now everything is one header and I will separate out the implementation



      #pragma once
      #include <cstdint>
      #include <vector>
      #include <iostream>
      #include <iomanip>
      #include <algorithm>
      #include <functional>
      #include <type_traits>

      template<typename T>
      class LiteMatrix
      {
      public:
      LiteMatrix(const size_t &rows, const size_t &cols);
      LiteMatrix(const size_t &rows, const size_t &cols, const std::vector<T>&data);
      ~LiteMatrix() = default;

      LiteMatrix(const LiteMatrix &rhs) = default; // copy constructor
      LiteMatrix(LiteMatrix && rhs) = default; // move constructor

      LiteMatrix& operator=(const LiteMatrix& rhs) = default; // copy assignment
      LiteMatrix& operator=(LiteMatrix&& rhs) = default; // move assignment

      LiteMatrix& zeroes();
      LiteMatrix& ones();

      LiteMatrix operator+(const LiteMatrix<T> &rhs);
      LiteMatrix& operator+=(const LiteMatrix<T>& rhs);
      LiteMatrix operator-(const LiteMatrix<T> &rhs);
      LiteMatrix& operator-=(const LiteMatrix<T>& rhs);
      LiteMatrix operator*(const LiteMatrix<T> &rhs);
      LiteMatrix& operator*=(const LiteMatrix<T>& rhs);
      T& operator()(const size_t &rIndex, const size_t &cIndex);

      LiteMatrix operator*(const T &rhs);
      LiteMatrix& operator*=(const T &rhs);

      bool operator!=(const LiteMatrix<T>& rhs) const;
      bool operator==(const LiteMatrix<T>& rhs) const;

      template<typename T>
      friend std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs);

      size_t rowCount() const;
      size_t colCount() const;

      bool isAddSubLegal(const LiteMatrix& rhs) const;
      bool isMultLegal(const LiteMatrix& rhs) const;

      void setMatrix(const std::vector<T>& val);
      void setElement(const size_t row, const size_t col, const T& val);
      void setRow(const size_t row, const std::vector<T> val);
      void setCol(const size_t col, const std::vector<T> val);
      T getElement(const size_t row, const size_t col) const;

      LiteMatrix& transpose();

      private:
      size_t m_rows;
      size_t m_cols;

      std::vector<T> m_mat;
      };

      //#include "LiteMatrix.tcc"

      template<typename T>
      LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols)
      : m_rows(rows), m_cols(cols)
      {
      m_mat = std::vector<T>(rows * cols);
      }

      template<typename T>
      LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols, const std::vector<T>& data)
      : m_rows(rows), m_cols(cols), m_mat(data)
      {
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::zeroes()
      {
      std::fill(m_mat.begin(), m_mat.end(), 0);

      return *this;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::ones()
      {
      std::fill(m_mat.begin(), m_mat.end(), 1);

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator+(const LiteMatrix& rhs)
      {
      LiteMatrix ret(*this);
      ret += rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator+=(const LiteMatrix& rhs)
      {
      if (!isAddSubLegal(rhs))
      throw std::range_error("Matrix sizes are not compatiblen");

      std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
      m_mat.begin(), std::plus<>());

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator-(const LiteMatrix& rhs)
      {
      LiteMatrix ret(*this);
      ret -= rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator-=(const LiteMatrix& rhs)
      {
      if (!isAddSubLegal(rhs))
      throw std::range_error("Matrix sizes are not compatiblen");

      std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
      m_mat.begin(), std::minus<>());

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator*(const LiteMatrix& rhs)
      {
      LiteMatrix ret(*this);
      ret *= rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator*=(const LiteMatrix& rhs)
      {
      if (!isMultLegal(rhs))
      throw std::range_error("Matrix index are not compatiblen");

      LiteMatrix<T> temp(m_rows, rhs.m_cols);

      for (size_t i = 0; i < m_rows; i++)
      {
      for (size_t j = 0; j < m_cols; ++j)
      {
      for (size_t k = 0; k < m_cols; ++k)
      {
      temp.m_mat[i * rhs.m_cols + j] += m_mat[i * m_cols + k] * rhs.m_mat[j + k * m_cols];
      }
      }
      }

      *this = std::move(temp);

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator*(const T& rhs)
      {
      LiteMatrix ret(*this);
      ret *= rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator*=(const T& rhs)
      {
      std::transform(m_mat.begin(), m_mat.end(), m_mat.begin(),
      std::bind(std::multiplies<T>(), std::placeholders::_1, rhs));

      return *this;
      }

      template<typename T>
      T& LiteMatrix<T>::operator()(const size_t& rIndex, const size_t& cIndex)
      {
      return m_mat[rIndex * m_cols + cIndex];
      }

      template<typename T>
      bool LiteMatrix<T>::operator!=(const LiteMatrix& rhs) const
      {
      bool isNotEqual = false;

      for (size_t i = 0; i < m_rows; i++)
      {
      for (size_t j = 0; j < m_cols; ++j)
      {
      isNotEqual = std::numeric_limits<T>::epsilon() <=
      std::abs(m_mat[i * m_cols + j] - rhs.m_mat[i * m_cols + j]);
      if (isNotEqual)
      break;
      }
      }
      return isNotEqual;
      }

      template<typename T>
      bool LiteMatrix<T>::operator==(const LiteMatrix& rhs) const
      {
      return !(*this != rhs);
      }

      template<typename T>
      std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs)
      {
      for (size_t i = 0; i < rhs.m_rows; ++i)
      {
      for (size_t j = 0; j < rhs.m_cols; ++j)
      os << std::setw(5) << std::setprecision(2) << rhs.m_mat[i * rhs.m_cols + j] << ' ';

      os << 'n';
      }
      return os;
      }

      template<typename T>
      size_t LiteMatrix<T>::rowCount() const
      {
      return m_rows;
      }

      template<typename T>
      size_t LiteMatrix<T>::colCount() const
      {
      return m_cols;
      }

      template<typename T>
      bool LiteMatrix<T>::isAddSubLegal(const LiteMatrix& rhs) const
      {
      return ((m_rows == rhs.m_rows) && (m_cols == rhs.m_cols));
      }

      template<typename T>
      bool LiteMatrix<T>::isMultLegal(const LiteMatrix& rhs) const
      {
      return (m_cols == rhs.m_rows);
      }

      template<typename T>
      void LiteMatrix<T>::setMatrix(const std::vector<T>& val)
      {
      std::copy(val.begin(), val.end(), m_mat.begin());
      return;
      }

      template<typename T>
      void LiteMatrix<T>::setElement(const size_t row, const size_t col, const T& val)
      {
      m_mat.at(row * m_rows + col) = val;
      return;
      }

      template<typename T>
      void LiteMatrix<T>::setRow(const size_t row, const std::vector<T> val)
      {
      if(row >= m_rows)
      throw std::range_error("Matrix index is out of rangen");
      if (val.size() > m_cols)
      {
      throw std::range_error("Data size is too largen");
      }

      std::copy(val.begin(), val.end(), m_mat.begin() + row * m_cols);
      }

      template<typename T>
      void LiteMatrix<T>::setCol(const size_t col, const std::vector<T> val)
      {
      if (col >= m_cols)
      throw std::range_error("Matrix index is out of rangen");
      if (val.size() > m_rows)
      {
      throw std::range_error("Data size is too largen");
      }

      for (size_t i = 0; i != val.size(); i++)
      {
      m_mat[col + i * m_rows] = val[i];
      }
      }

      template<typename T>
      T LiteMatrix<T>::getElement(const size_t row, const size_t col) const
      {
      return m_mat.at(row * m_rows + col);
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::transpose()
      {
      // TODO: insert return statement here
      if (m_cols != 1 && m_rows != 1)
      {
      decltype(m_cols) colStart = 0;
      for (size_t i = 0; i < m_rows; ++i)
      {
      for (size_t j = colStart; j < m_cols; ++j)
      {
      std::iter_swap(m_mat.begin() + (i * m_cols + j),
      m_mat.begin() + (j * m_rows + i));
      }
      ++colStart;
      }
      }

      std::swap(m_rows, m_cols);

      return *this;
      }


      main.cpp



      #include "LiteMatrix.h"
      #include <iostream>

      int main()
      {
      LiteMatrix<double> m1(2, 2);
      std::cout << "Row Count: " << m1.rowCount() << std::endl;
      std::cout << "Column Count: " << m1.colCount() << std::endl;

      LiteMatrix<double> m2(2, 2);
      std::cout << m1.ones();
      std::cout << m2.ones();

      LiteMatrix<double> m4(2, 2, std::vector<double>{1, 2, 3, 4});
      LiteMatrix<double> m5(2, 1);
      m5.setMatrix(std::vector<double> {7.5, 10.8});

      LiteMatrix<double> m6(3, 3, std::vector<double>{1, 2, 3, 4, 5, 6, 7, 8, 9});
      std::cout << "m6n";
      std::cout << m6;
      std::cout << m6.transpose();

      LiteMatrix<double> m7(3, 1, std::vector<double>{1, 2, 3});
      std::cout << "m7n";
      std::cout << m7;
      std::cout << m7.transpose();

      m1.setElement(0, 0, 19.0);
      std::cout << m1.getElement(0, 0);

      std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m2) << std::endl;

      m1 += m1;
      std::cout << "m1 + m2n" << m1 + m2;
      std::cout << "m2 - m2n" << m2 - m2;
      std::cout << "m1 * m2n" << m1 * m2;

      std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
      std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

      m1.ones();

      std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
      std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

      LiteMatrix<double> m3(10, 10);
      m3.ones();

      std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m3) << std::endl;

      m3.setRow(0, std::vector<double> {22, 33, 44, 55});
      m3.setCol(9, std::vector<double> {66, 77, 88, 99});
      std::cout << m3;
      if(m1.isAddSubLegal(m3))
      m3 += m1;

      return 0;
      }









      share|improve this question







      New contributor




      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      I wanted to make a matrix template class to see if I can learn how to use templates, work on figuring out the indexing in loops, and making an interface so the user can know if an operation will work. Eventually I would like to add more cache optimization, calculating the inverse, and other ways to get data into the matrix such as raw pointers.



      For now everything is one header and I will separate out the implementation



      #pragma once
      #include <cstdint>
      #include <vector>
      #include <iostream>
      #include <iomanip>
      #include <algorithm>
      #include <functional>
      #include <type_traits>

      template<typename T>
      class LiteMatrix
      {
      public:
      LiteMatrix(const size_t &rows, const size_t &cols);
      LiteMatrix(const size_t &rows, const size_t &cols, const std::vector<T>&data);
      ~LiteMatrix() = default;

      LiteMatrix(const LiteMatrix &rhs) = default; // copy constructor
      LiteMatrix(LiteMatrix && rhs) = default; // move constructor

      LiteMatrix& operator=(const LiteMatrix& rhs) = default; // copy assignment
      LiteMatrix& operator=(LiteMatrix&& rhs) = default; // move assignment

      LiteMatrix& zeroes();
      LiteMatrix& ones();

      LiteMatrix operator+(const LiteMatrix<T> &rhs);
      LiteMatrix& operator+=(const LiteMatrix<T>& rhs);
      LiteMatrix operator-(const LiteMatrix<T> &rhs);
      LiteMatrix& operator-=(const LiteMatrix<T>& rhs);
      LiteMatrix operator*(const LiteMatrix<T> &rhs);
      LiteMatrix& operator*=(const LiteMatrix<T>& rhs);
      T& operator()(const size_t &rIndex, const size_t &cIndex);

      LiteMatrix operator*(const T &rhs);
      LiteMatrix& operator*=(const T &rhs);

      bool operator!=(const LiteMatrix<T>& rhs) const;
      bool operator==(const LiteMatrix<T>& rhs) const;

      template<typename T>
      friend std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs);

      size_t rowCount() const;
      size_t colCount() const;

      bool isAddSubLegal(const LiteMatrix& rhs) const;
      bool isMultLegal(const LiteMatrix& rhs) const;

      void setMatrix(const std::vector<T>& val);
      void setElement(const size_t row, const size_t col, const T& val);
      void setRow(const size_t row, const std::vector<T> val);
      void setCol(const size_t col, const std::vector<T> val);
      T getElement(const size_t row, const size_t col) const;

      LiteMatrix& transpose();

      private:
      size_t m_rows;
      size_t m_cols;

      std::vector<T> m_mat;
      };

      //#include "LiteMatrix.tcc"

      template<typename T>
      LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols)
      : m_rows(rows), m_cols(cols)
      {
      m_mat = std::vector<T>(rows * cols);
      }

      template<typename T>
      LiteMatrix<T>::LiteMatrix(const size_t & rows, const size_t & cols, const std::vector<T>& data)
      : m_rows(rows), m_cols(cols), m_mat(data)
      {
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::zeroes()
      {
      std::fill(m_mat.begin(), m_mat.end(), 0);

      return *this;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::ones()
      {
      std::fill(m_mat.begin(), m_mat.end(), 1);

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator+(const LiteMatrix& rhs)
      {
      LiteMatrix ret(*this);
      ret += rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator+=(const LiteMatrix& rhs)
      {
      if (!isAddSubLegal(rhs))
      throw std::range_error("Matrix sizes are not compatiblen");

      std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
      m_mat.begin(), std::plus<>());

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator-(const LiteMatrix& rhs)
      {
      LiteMatrix ret(*this);
      ret -= rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator-=(const LiteMatrix& rhs)
      {
      if (!isAddSubLegal(rhs))
      throw std::range_error("Matrix sizes are not compatiblen");

      std::transform(m_mat.begin(), m_mat.end(), rhs.m_mat.begin(),
      m_mat.begin(), std::minus<>());

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator*(const LiteMatrix& rhs)
      {
      LiteMatrix ret(*this);
      ret *= rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator*=(const LiteMatrix& rhs)
      {
      if (!isMultLegal(rhs))
      throw std::range_error("Matrix index are not compatiblen");

      LiteMatrix<T> temp(m_rows, rhs.m_cols);

      for (size_t i = 0; i < m_rows; i++)
      {
      for (size_t j = 0; j < m_cols; ++j)
      {
      for (size_t k = 0; k < m_cols; ++k)
      {
      temp.m_mat[i * rhs.m_cols + j] += m_mat[i * m_cols + k] * rhs.m_mat[j + k * m_cols];
      }
      }
      }

      *this = std::move(temp);

      return *this;
      }

      template<typename T>
      LiteMatrix<T> LiteMatrix<T>::operator*(const T& rhs)
      {
      LiteMatrix ret(*this);
      ret *= rhs;
      return ret;
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::operator*=(const T& rhs)
      {
      std::transform(m_mat.begin(), m_mat.end(), m_mat.begin(),
      std::bind(std::multiplies<T>(), std::placeholders::_1, rhs));

      return *this;
      }

      template<typename T>
      T& LiteMatrix<T>::operator()(const size_t& rIndex, const size_t& cIndex)
      {
      return m_mat[rIndex * m_cols + cIndex];
      }

      template<typename T>
      bool LiteMatrix<T>::operator!=(const LiteMatrix& rhs) const
      {
      bool isNotEqual = false;

      for (size_t i = 0; i < m_rows; i++)
      {
      for (size_t j = 0; j < m_cols; ++j)
      {
      isNotEqual = std::numeric_limits<T>::epsilon() <=
      std::abs(m_mat[i * m_cols + j] - rhs.m_mat[i * m_cols + j]);
      if (isNotEqual)
      break;
      }
      }
      return isNotEqual;
      }

      template<typename T>
      bool LiteMatrix<T>::operator==(const LiteMatrix& rhs) const
      {
      return !(*this != rhs);
      }

      template<typename T>
      std::ostream& operator<<(std::ostream& os, const LiteMatrix<T>& rhs)
      {
      for (size_t i = 0; i < rhs.m_rows; ++i)
      {
      for (size_t j = 0; j < rhs.m_cols; ++j)
      os << std::setw(5) << std::setprecision(2) << rhs.m_mat[i * rhs.m_cols + j] << ' ';

      os << 'n';
      }
      return os;
      }

      template<typename T>
      size_t LiteMatrix<T>::rowCount() const
      {
      return m_rows;
      }

      template<typename T>
      size_t LiteMatrix<T>::colCount() const
      {
      return m_cols;
      }

      template<typename T>
      bool LiteMatrix<T>::isAddSubLegal(const LiteMatrix& rhs) const
      {
      return ((m_rows == rhs.m_rows) && (m_cols == rhs.m_cols));
      }

      template<typename T>
      bool LiteMatrix<T>::isMultLegal(const LiteMatrix& rhs) const
      {
      return (m_cols == rhs.m_rows);
      }

      template<typename T>
      void LiteMatrix<T>::setMatrix(const std::vector<T>& val)
      {
      std::copy(val.begin(), val.end(), m_mat.begin());
      return;
      }

      template<typename T>
      void LiteMatrix<T>::setElement(const size_t row, const size_t col, const T& val)
      {
      m_mat.at(row * m_rows + col) = val;
      return;
      }

      template<typename T>
      void LiteMatrix<T>::setRow(const size_t row, const std::vector<T> val)
      {
      if(row >= m_rows)
      throw std::range_error("Matrix index is out of rangen");
      if (val.size() > m_cols)
      {
      throw std::range_error("Data size is too largen");
      }

      std::copy(val.begin(), val.end(), m_mat.begin() + row * m_cols);
      }

      template<typename T>
      void LiteMatrix<T>::setCol(const size_t col, const std::vector<T> val)
      {
      if (col >= m_cols)
      throw std::range_error("Matrix index is out of rangen");
      if (val.size() > m_rows)
      {
      throw std::range_error("Data size is too largen");
      }

      for (size_t i = 0; i != val.size(); i++)
      {
      m_mat[col + i * m_rows] = val[i];
      }
      }

      template<typename T>
      T LiteMatrix<T>::getElement(const size_t row, const size_t col) const
      {
      return m_mat.at(row * m_rows + col);
      }

      template<typename T>
      LiteMatrix<T>& LiteMatrix<T>::transpose()
      {
      // TODO: insert return statement here
      if (m_cols != 1 && m_rows != 1)
      {
      decltype(m_cols) colStart = 0;
      for (size_t i = 0; i < m_rows; ++i)
      {
      for (size_t j = colStart; j < m_cols; ++j)
      {
      std::iter_swap(m_mat.begin() + (i * m_cols + j),
      m_mat.begin() + (j * m_rows + i));
      }
      ++colStart;
      }
      }

      std::swap(m_rows, m_cols);

      return *this;
      }


      main.cpp



      #include "LiteMatrix.h"
      #include <iostream>

      int main()
      {
      LiteMatrix<double> m1(2, 2);
      std::cout << "Row Count: " << m1.rowCount() << std::endl;
      std::cout << "Column Count: " << m1.colCount() << std::endl;

      LiteMatrix<double> m2(2, 2);
      std::cout << m1.ones();
      std::cout << m2.ones();

      LiteMatrix<double> m4(2, 2, std::vector<double>{1, 2, 3, 4});
      LiteMatrix<double> m5(2, 1);
      m5.setMatrix(std::vector<double> {7.5, 10.8});

      LiteMatrix<double> m6(3, 3, std::vector<double>{1, 2, 3, 4, 5, 6, 7, 8, 9});
      std::cout << "m6n";
      std::cout << m6;
      std::cout << m6.transpose();

      LiteMatrix<double> m7(3, 1, std::vector<double>{1, 2, 3});
      std::cout << "m7n";
      std::cout << m7;
      std::cout << m7.transpose();

      m1.setElement(0, 0, 19.0);
      std::cout << m1.getElement(0, 0);

      std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m2) << std::endl;

      m1 += m1;
      std::cout << "m1 + m2n" << m1 + m2;
      std::cout << "m2 - m2n" << m2 - m2;
      std::cout << "m1 * m2n" << m1 * m2;

      std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
      std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

      m1.ones();

      std::cout << "m1 != m2: " << (m1 != m2) << std::endl;
      std::cout << "m1 == m2: " << (m1 == m2) << std::endl;

      LiteMatrix<double> m3(10, 10);
      m3.ones();

      std::cout << "Is Addition Legal: " << m1.isAddSubLegal(m3) << std::endl;

      m3.setRow(0, std::vector<double> {22, 33, 44, 55});
      m3.setCol(9, std::vector<double> {66, 77, 88, 99});
      std::cout << m3;
      if(m1.isAddSubLegal(m3))
      m3 += m1;

      return 0;
      }






      c++ matrix c++14 template vectors






      share|improve this question







      New contributor




      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question







      New contributor




      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question






      New contributor




      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 10 mins ago









      Eddie C.

      11




      11




      New contributor




      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Eddie C. is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          Eddie C. is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210791%2fsimple-matrix-template-class%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          Eddie C. is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          Eddie C. is a new contributor. Be nice, and check out our Code of Conduct.













          Eddie C. is a new contributor. Be nice, and check out our Code of Conduct.












          Eddie C. is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210791%2fsimple-matrix-template-class%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Create new schema in PostgreSQL using DBeaver

          Deepest pit of an array with Javascript: test on Codility

          Costa Masnaga