Simple matrix class C++14
I'm not sure how I feel about you hardcoding that this should be a 4x4 matrix of floats, and that it should be column major. It seems straightforward enough to make a templated class like so

template &lt;typename T, size_t numRows, size_t numCols&gt;
class Matrix {
...
};

using mat4 = Matrix&lt;float, 4, 4&gt;;


It might also be worthwhile to have a boolean template parameter for whether or not it should be row or column major; in my experience many applications assume something is row major, and interfacing with your application might yield some unexpected issues.

If you do so, then I think adding a constructor to switch row/column major would be worthwhile as well.

I personally like using operator() instead of operator[] for getting a value at a given row and column; I feel like in general it shouldn't be up to the user to manually calculate the 1d index.  Something along the lines of this:

constexpr const T&amp; operator()(size_t row, size_t col) const noexcept 
{
    return matrix[col * numCols + row];
}

constexpr T&amp; operator()(size_t row, size_t col) noexcept
{
    return matrix[col * numCols + row];
}


I also generally assume that at() (or similar) will be provided if indexing (or operator()-like access) is provided.

Don't use a member function like print(); instead implement operator&lt;&lt; so people can use it with their own streams as desired.  I see you're using printf - why? I've definitely used it before in my programs, but I usually think of it as a code-smell. If you want to add printf support that's fine, but I would argue that streams should be prioritized.

Your operator== is unnecessarily complicated - std::array implements it.

I don't like using this-&gt; to refer to member functions; just use them.  Then your operator!= becomes return !operator==(other).

operator+= and operator*= can be done using std::transform.

You should implement iterators for your matrix as well. Whether you make them row-major or column-major shouldn't matter, but be consistent (assuming you make it possible to switch between orientations). No matter the orientation, the iteration order should be the same.

You should add some improved matrix multiplication algorithms (or, ideally, use a library that does it for you). With some SFINAE wizardry you can probably make a vectorized version, a tiled version, etc.  Probably only necessary if you actually make it possible to use larger matrices, although vectorization will probably still be a bit faster even for a small one.