Entwicklung einer einfachen Matrizenklasse
-
Wie oft brauchst Du das denn? Sonst musst Du es Dir eben merken.
@zeropage sagte in Entwicklung einer einfachen Matrizenklasse:
Die Syntax
f[x][y]
mit Stichwort Proxy-Klasse kapiere ich einfach nicht.So zB:
#include <iostream> #include <vector> template<typename T> class mat2d_t { public: using value_type = T; using reference_type = T&; using size_type = typename std::vector<T>::size_type; class row_t { T* row_data; size_type num_cols; // fuer evtl range-check public: row_t(T *row_data, size_type num_cols) : row_data{ row_data }, num_cols{ num_cols } {} T& operator[](size_type col) { return row_data[col]; } }; private: size_type num_cols = 0; std::vector<T> data; public: mat2d_t() = default; mat2d_t(size_type rows, size_type cols, value_type const &value = value_type{}) : num_cols { cols }, data ( rows * cols, value ) {} row_t operator[](size_type row) { return { &data[row * num_cols], num_cols }; } }; int main() { mat2d_t<int> mat2d(2, 5, 42); for (std::size_t y{}, i{ 1 }; y < 2; ++y) for (std::size_t x{}; x < 5; ++x, ++i) mat2d[y][x] = i; for (std::size_t y{}, i{ 1 }; y < 2; ++y, std::cout.put('\n')) for (std::size_t x{}; x < 5; ++x, ++i, std::cout.put(' ')) std::cout << mat2d[y][x]; }
-
Besten Dank mal wieder.
Mache jetzt aber Feierabend , guts Nächtle...
-
-
Jupp.
-
@zeropage sagte in Entwicklung einer einfachen Matrizenklasse:
Und, das ich mich für die Zeilen- und Spaltenanzahl auf std::size_t festlegen möchte. "einfache Matrizenklasse" soll wortwörtlich gelten.
Das Template dient doch aber dazu, dass die int, double oder sonstwas in deiner Matrix speichern kannst - irgendwas, mit dem man rechnen kann wie zum Beispiel big integers.
Oder warum kommst du auf das size_t? Andererseits wird es vom vector ja schon automatisch vorgegeben.
-
Die Typ der Elemente der Matrix sollen natürlich möglichst beliebig sein, also alles mit was man rechnen kann.
Ich meinte jetzt
std::size_t columns_
. Weil ich mir einbilde, dafür auch schon mal ein Template gesehen zu haben. Kann mich aber voll irren, alleine weil ich mir etwas anderes alssize_t
gar nicht vorstellen kann.
-
@zeropage sagte in Entwicklung einer einfachen Matrizenklasse:
Weil ich mir einbilde, dafür auch schon mal ein Template gesehen zu haben.
Du meinst einen Template-Typ-Parameter für den Typ der Größenangaben?
-
Richtig. Können aber auch Gespenster in meinem Kopf sein.
-
Vllt hilft das hier etwas weiter:
https://www.c-plusplus.net/forum/topic/348029/array2d-evolution-von-manueller-speicherverwaltung-zur-stl
-
@DocShoe Den Thread habe ich gesucht, aber nicht mehr gefunden
-
Ein Mini-Zwischenstand. Eigentlich dachte ich mir, mit der Proxy-Klasse wäre dieses Kapitel abgeschlossen, aber bin mir nicht mehr sicher. Ist das soweit in Ordnung?
template<typename T> class Mat2D_T { public: using valType = T; using size_t = std::size_t; class Row { valType* row_data; size_t cols_ = 0; public: Row(valType* row_data, const size_t columns) : row_data{ row_data }, cols_{ columns } {} valType& operator[](const size_t column) { if (column >= cols_) throw std::out_of_range("operator[](): column: " + std::to_string(column)); return row_data[column]; } }; Mat2D_T() = default; Mat2D_T(const size_t rows, const size_t columns) : columns_{ columns }, elements_(rows * columns) {} size_t rows() const { return elements_.size() / columns_; //kann man sich die Länge nicht von der Klasse Row geben lassen? } size_t columns() const { return columns_; } Row operator[](const size_t row) { if (row >= rows()) throw std::out_of_range("operator[](): row: " + std::to_string(row)); return { &elements_[row * columns_], columns_ }; } /*diese Funktionen werde ich später doch bestimmt auch noch benötigen?*/ valType element(const size_t row, const size_t column) const { const size_t idx = toLinearIndex(row, column); return elements_[idx]; } valType operator()(const size_t row, const size_t column) const { const size_t idx = toLinearIndex(row, column); return elements_[idx]; } void setElement(const size_t row, const size_t column, const valType& v) { const size_t idx = toLinearIndex(row, column); elements_[idx] = v; } private: size_t toLinearIndex(const size_t row, const size_t column) const { if (row >= rows()) throw std::out_of_range("toLinearIndex(): row: " + std::to_string(row)); if (column >= columns()) throw std::out_of_range("toLinearIndex(): column: " + std::to_string(column)); return columns() * row + column; } ///////////////////////////////////////////////////////////////////////// size_t columns_ = 0; std::vector<valType> elements_; };
-
Eine Sache richtig zu machen ist um Welten schwerer, als sie funktionierend zu machen.
Ich wollte die Methoden in eine .cpp auslagern, um mehr Platz im Header zu haben und bekomme lauter
unresolved externals
-
@zeropage Du kannst Templates nicht so einfach in eine Cpp auslagern.
-
Stimmt wohl.
-
Noch der
operator*()
und dann ist der Grundaufbau doch eigentlich fertig?Mat2D_T operator*(const Mat2D_T& mT) const { if (columns() != mT.rows()) throw std::exception("operator*()"); Mat2D_T nmT(rows(), mT.columns()); valType v = {}; for (size_t c = 0; c < mT.columns(); ++c) { for (size_t r = 0; r < rows(); ++r) { v = element(r, 0) * mT.element(0, c); for (size_t l = 1; l < columns(); ++l) { v += element(r, l) * mT.element(l, c); } nmT[r][c] = v; } v = {}; } return nmT; }
-
@zeropage sagte in Entwicklung einer einfachen Matrizenklasse:
return elements_.size() / columns_; //kann man sich die Länge nicht von der Klasse Row geben lassen?
Wann existiert denn immer ein
Row
?
-
@Swordfish Immer nur wenn
operator[]()
aufgerufen wird?
-
Eben. Wenn Du die anzahl der rows nicht jedes mahl ausrechnen willst dann musst Du sie Dir wo merken.
-
Alles klar
-
Frage aus Neugier:
valType operator()(const size_t row, const size_t column) const { const size_t idx = toLinearIndex(row, column); return elements_[idx]; }
benötige ich eigentlich nicht mehr, mich würde aber interessieren, wie man
Mat2D_T<int> mat(3, 4); mat(1, 1) = 5;
realisieren kann?