#include <array>
#include <type_traits>
#include <iostream>
#include <iomanip>

// Get rid of any "Waah, you didn't use that!" warnings.
// See http://stackoverflow.com/a/31654792/5386374
#define UNUSED(x) [&x]{}()

// This example uses std::array for the actual array, since it's compile-time anyways.
// This, in turn, lets it declare a lot of functions constexpr.
// Const-correctness omitted for brevity.  Remember to restore it for actual code.
template<size_t Rows, size_t Cols>
class Matrix {
    std::array<std::array<double, Cols>, Rows> mat;

  public:
    // Default constructor. Clang _really_ likes braced initialiser lists.
    constexpr Matrix() : mat{{{{0}}}} {}

    // Array constructor.
    constexpr Matrix(const decltype(mat)& arr) : mat(arr) {}

    // -----

    // Subscript operators.

    // Generic operator.  Matrix<x, y>, where x != 1 && y != 1.
    // Does what normal subscript operators do.
    template<bool R = (Rows == 1), bool C = (Cols == 1)>
    auto& operator[](std::enable_if_t<!R && !C, size_t> i) {
        return mat[i];
    }

    // Magic operator.  Matrix<1, x>, where x != 1.
    template<bool R = (Rows == 1), bool C = (Cols == 1)>
    auto& operator[](std::enable_if_t<(R && !C), size_t> i) {
        return mat[0][i];
    }

    // Magic operator.  Matrix<x, 1>, where x != 1.
    template<bool R = (Rows == 1), bool C = (Cols == 1)>
    auto& operator[](std::enable_if_t<C && !R, size_t> i) {
        return mat[i][0];
    }

    // Scalar matrix operator.  Matrix<1, 1>.
    // Just returns mat[0][0], for simplicity's sake.  Might want to make it do something
    //  more complex in your actual class.
    template<bool R = (Rows == 1), bool C = (Cols == 1)>
    auto& operator[](std::enable_if_t<R && C, size_t> i) {
        return mat[0][0];
    }

    // -----

    // A few interface helpers.

    // Simple begin() & end(), for example's sake.
    // A better version would begin at mat[0][0] and end at mat[Rows - 1][Cols - 1].
    constexpr auto begin() const { return mat.begin(); }
    constexpr auto   end() const { return mat.end(); }

    // Generic helpers.
    constexpr size_t    size() const { return mat.size() * mat[0].size(); }
    constexpr size_t    rows() const { return mat.size(); }
    constexpr size_t    cols() const { return mat[0].size(); }

    // 1D Matrix helpers.
    constexpr bool    is_one_d() const { return (Rows == 1) || (Cols == 1); }
    constexpr bool     one_row() const { return Rows == 1; }
    constexpr size_t dimension() const { return (one_row() ? cols() : rows()); }

    // -----

    // Output.
    // Would need modification if better begin() & end() are implemented.
    friend std::ostream& operator<<(std::ostream& str, const Matrix<Rows, Cols>& m) {
        for (auto& row : m) {
            for (auto& elem : row) {
                str << std::setw(6) << elem << ' ';
            }
            str << '\n';
        }
        str << std::endl;
        return str;
    }
};

// -----

// This should really use if constexpr, but online compilers don't really support it yet.
template<size_t Rows, size_t Cols>
void fill(Matrix<Rows, Cols>& m, std::enable_if_t<(Rows == 1) || (Cols == 1), int> dummy = 0) {
    UNUSED(dummy);
    
    //for (size_t i = 0; i < (m.one_row() ? m.cols() : m.rows()); i++) {
    for (size_t i = 0; i < m.dimension(); i++) {
        m[i] = (i ? i : 0.5) * (i ? i : 0.5);
    }
}

template<size_t Rows, size_t Cols>
void fill(Matrix<Rows, Cols>& m, std::enable_if_t<!((Rows == 1) || (Cols == 1)), int> dummy = 0) {
    UNUSED(dummy);
    
    for (size_t i = 0; i < m.rows(); i++) {
        for (size_t j = 0; j < m.cols(); j++) {
            m[i][j] = (i ? i : 0.5) * (j ? j : 0.5) + (i >= j ? 0.1 : -0.2);
        }
    }
}

// -----

int main() {
    Matrix<3, 4> m34;
    fill(m34);
    m34[2][1] = 21.21;
    std::cout << m34;
    
    // -----
    
    Matrix<1, 4> m14;
    fill(m14);
    m14[3] = 03.03;
    std::cout << m14;
    
    // -----
    
    Matrix<3, 1> m31;
    fill(m31);
    m31[2] = 20.20;
    std::cout << m31;
    
    std::array<std::array<double, 2>, 2> arr = 
        { 8.8, -16.61, -8.8, 16.61 };
    
    // -----
    
    Matrix<2, 2> m22 = arr;
    std::cout << m22;
}