Beispiellösung

#ifndef MATRIX_HPP
#define MATRIX_HPP

#include <cassert>
#include <cstddef>

enum class StorageOrder {ColMajor, RowMajor};

template<typename T>
struct Matrix {
   const std::size_t m; /* number of rows */
   const std::size_t n; /* number of columns */
   const std::size_t incRow; /* stride between subsequent rows */
   const std::size_t incCol; /* stride between subsequent columns */
   T* data;

   Matrix(std::size_t m, std::size_t n, StorageOrder order) :
         m(m), n(n),
         incRow(order == StorageOrder::ColMajor? 1: n),
         incCol(order == StorageOrder::RowMajor? 1: m),
         data(new T[m*n]) {
   }

   ~Matrix() {
      delete[] data;
   }

   Matrix(const Matrix&) = delete;
   Matrix& operator=(const Matrix&) = delete;

   const T& operator()(std::size_t i, std::size_t j) const {
      assert(i < m && j < n);
      return data[i*incRow + j*incCol];
   }
   
   T& operator()(std::size_t i, std::size_t j) {
      assert(i < m && j < n);
      return data[i*incRow + j*incCol];
   }
};

#endif
#include <iomanip>
#include <iostream>
#include "matrix.hpp"

int main() {
   Matrix<double> A(7, 8, StorageOrder::ColMajor);
   for (std::size_t j = 0; j < A.n; ++j) {
      for (std::size_t i = 0; i < A.m; ++i) {
	 A(i, j) = i * A.n + j;
      }
   }
   std::cout << "A:" << std::endl;
   for (std::size_t i = 0; i < A.m; ++i) {
      for (std::size_t j = 0; j < A.n; ++j) {
	 std::cout << " " << std::setw(8) << A(i, j);
      }
      std::cout << std::endl;
   }

   Matrix<float> B(3, 3, StorageOrder::RowMajor);
   for (std::size_t i = 0; i < B.m; ++i) {
      for (std::size_t j = 0; j < B.n; ++j) {
	 B(i, j) = j * B.m + i;
      }
   }
   std::cout << std::endl << "B:" << std::endl;
   for (std::size_t i = 0; i < B.m; ++i) {
      for (std::size_t j = 0; j < B.n; ++j) {
	 std::cout << " " << std::setw(8) << B(i, j);
      }
      std::cout << std::endl;
   }
}
theon$ g++ -Wall -o test-matrix test-matrix.cpp
theon$ ./test-matrix
A:
        0        1        2        3        4        5        6        7
        8        9       10       11       12       13       14       15
       16       17       18       19       20       21       22       23
       24       25       26       27       28       29       30       31
       32       33       34       35       36       37       38       39
       40       41       42       43       44       45       46       47
       48       49       50       51       52       53       54       55

B:
        0        3        6
        1        4        7
        2        5        8
theon$ 

Gibt es auch Datentypen, mit denen es nicht klappt?

An der folgenden Stelle setzt der new-Operator voraus, dass es einen parameterlosen Konstruktor für T gibt, da wir keine Parameter spezifizieren:

   Matrix(std::size_t m, std::size_t n, StorageOrder order) :
	 /* ... */
         data(new T[m*n]) {
   }

Hier ist ein minimalistisches Beispiel mit der Klasse Double, die keinen parameterlosen Konstruktor zur Verfügung stellt:

#include <iomanip>
#include <iostream>
#include "matrix.hpp"

struct Double {
   Double(double value) : value(value) {
   }
   double value;
};

int main() {
   Matrix<Double> A(7, 8, StorageOrder::ColMajor);
}
theon$ g++ -Wall -o bad-matrix bad-matrix.cpp
In file included from bad-matrix.cpp:3:
matrix.hpp: In instantiation of 'Matrix<T>::Matrix(std::size_t, std::size_t, StorageOrder) [with T = Double; std::size_t = long unsigned int]':
bad-matrix.cpp:12:49:   required from here
matrix.hpp:21:15: error: no matching function for call to 'Double::Double()'
   21 |          data(new T[m*n]) {
      |               ^~~~~~~~~~
bad-matrix.cpp:6:4: note: candidate: 'Double::Double(double)'
    6 |    Double(double value) : value(value) {
      |    ^~~~~~
bad-matrix.cpp:6:4: note:   candidate expects 1 argument, 0 provided
bad-matrix.cpp:5:8: note: candidate: 'constexpr Double::Double(const Double&)'
    5 | struct Double {
      |        ^~~~~~
bad-matrix.cpp:5:8: note:   candidate expects 1 argument, 0 provided
bad-matrix.cpp:5:8: note: candidate: 'constexpr Double::Double(Double&&)'
bad-matrix.cpp:5:8: note:   candidate expects 1 argument, 0 provided
theon$