Return row or column from a 2D array
Lack of modifiability

Your at(), row() and col() return copies. This means that once you construct your mat, it's permanently const. Also, for some Ts, this makes these functions unnecessarily expensive.

Prefer instead for at() to return a reference:

T&amp; at(size_t row, size_t col);
T const&amp; at(size_t row, size_t col) const;


Although, typically with the standard library, the at() member functions also do range checking. So consider some other non-throwing indexing mechanism (maybe operator()) and have at() defer to that one while doing bounds checking. Note that you don't need to pass the size_ts by reference-to-const, value is fine.

Now, for the other two, prefer instead:

std::vector&lt;std::reference_wrapper&lt;T&gt;&gt;       row(size_t );
std::vector&lt;std::reference_wrapper&lt;const T&gt;&gt; row(size_t ) const;
std::vector&lt;std::reference_wrapper&lt;T&gt;&gt;       col(size_t );
std::vector&lt;std::reference_wrapper&lt;const T&gt;&gt; col(size_t ) const;


reference_wrapper&lt;T&gt; since you can't have vector&lt;T&amp;&gt;.

Constructing those rows/cols

Since you're storing everything in row order, returning a row can just use the iterator-pair constructor of std::vector:

std::vector&lt;std::reference_wrapper&lt;T&gt;&gt; row(size_t r)
{
    auto start = m_values.begin() + r * ncol();
    return {start, start + ncol()};
}


Returning a column is much more annoying, but you definitely want to use reserve() to avoid any extra allocations:

std::vector&lt;std::reference_wrapper&lt;T&gt;&gt; col(size_t c)
{
    std::vector&lt;std::reference_wrapper&lt;T&gt;&gt; result;
    result.reserve(nrows());
    for (size_t r = 0; r &lt; nrows(); ++r) {
        result.push_back((*this)(r, c));
    }
    return result;
}


Where I'm assuming operator() is the non-throwing version of at.