Containerdesign bei beliebig vielen Dimensionen.
-
Hallo allerseits,
ich brüte gerade über einer generischen Lösung für mein Problem und wollte' fragen ob jmd. helfen kann.
Vorab das Problem:
1.
Ich benötige etwas in der Art eines mehrdimensionalen Arrays wobei die Anzahl an Dimensionen erst zur Laufzeit bekannt wird.
2.
Das Array ist nicht rechteckig.Z.B. könnte der 3D-Spezialfall wie ein geschnittenes Brot aussehen. Jedes 2D-Element (Schnitte) des 3D-Arrays (Brot) kann eine andere Größe aufweisen. So dann auch bei anderen Arrays (2D,4D,nD).
Bisherige Lösung:
Ich habe für jeden Spezialfall einen geschachtelten std::vector<T> benutzt. Nun nicht mehr nutzbar da ich beliebig viele Dimensionen handhaben muss.Wie würdet ihr das Problem erschlagen?
Regards
-
Den Typen könntest du über ein rekursives Template herleiten.
Operationen wären ähnlich zu implementieren.template<typename T, unsigned N> struct make_vector { typedef std::vector<std::vector<T, N-1>::vec_type> vec_type; } template<typename T> struct make_vector<T, 1> { typedef std::vector<T> vec_type; };
-
Clever
-
Nein, das passt nicht.
Du hast gesagt, die Anzahl der Dimensionen ist erst zur Laufzeit bekannt.
Das hier ist jedoch noch zur Compilezeit. Dort zwar gut und schön, aber eben noch zur Compilezeit.
-
Skym0sh0 schrieb:
Nein, das passt nicht.
Du hast gesagt, die Anzahl der Dimensionen ist erst zur Laufzeit bekannt.
Das hier ist jedoch noch zur Compilezeit. Dort zwar gut und schön, aber eben noch zur Compilezeit.Weniger das Problem. Ich denke mal dass sich der Bereich nicht im astronomischen Bereich bewegen wird sondern ziemlich sicher unter 10.
Das lässt sich problemlos behandeln.
-
goran schrieb:
Hallo allerseits,
ich brüte gerade über einer generischen Lösung für mein Problem und wollte' fragen ob jmd. helfen kann.
Vorab das Problem:
1.
Ich benötige etwas in der Art eines mehrdimensionalen Arrays wobei die Anzahl an Dimensionen erst zur Laufzeit bekannt wird.
2.
Das Array ist nicht rechteckig.Z.B. könnte der 3D-Spezialfall wie ein geschnittenes Brot aussehen. Jedes 2D-Element (Schnitte) des 3D-Arrays (Brot) kann eine andere Größe aufweisen. So dann auch bei anderen Arrays (2D,4D,nD).
Bisherige Lösung:
Ich habe für jeden Spezialfall einen geschachtelten std::vector<T> benutzt. Nun nicht mehr nutzbar da ich beliebig viele Dimensionen handhaben muss.Wie würdet ihr das Problem erschlagen?
Regards
Das macht eigentlich nur dann Sinn, wenn stets nur einzelne Elemente benötigt werden.
Folglich ist ein einfacher vector<T> erst einmal die richtige Datenstruktur.
Wenn die Anzahl der Dimensionen erst zur Laufzeit feststeht, muss das Zugriffstupel auch in irgendeiner dynamischen Struktur dargestellt sein, sagen wir vector<size_t>.
Da wir nichtvec[tupel]
schrieben können, besteht die Aufgabe eigentlich nur darin, eine Funktion (bzw. Funktor) zu schreiben, die das Zugriffstupel eineindeutig auf eine einzele Zahl abbildet.
-
Wenn ich kein Denkfehler reingebaut habe, sollte das hier funktionieren:
#include <iostream> #include <iterator> #include <vector> template<typename InputIterator, typename T> T multiply( InputIterator first, InputIterator last, T result ) { for(; first!=last; ++first) { result *= *first; } return result; } template<typename T> class vector_nd { private: std::vector<std::size_t> declaration; std::size_t dimensions; std::size_t elements; std::vector<T> data; std::vector<std::size_t> elements_in_dimension; public: vector_nd( const std::vector<std::size_t>& declaration ) : declaration( declaration ), dimensions ( declaration.size() ), elements ( multiply( declaration.begin(), declaration.end(), 1 ) ), data ( elements ) { elements_in_dimension.push_back( elements / declaration[0] ); for(std::size_t i=1; i!=dimensions; ++i) { elements_in_dimension.push_back( elements_in_dimension[i-1] / declaration[i] ); } // Standardwerte zum Testen: for(std::size_t i=0; i!=elements; ++i) { data[i] = i; } } const T& operator()( const std::vector<std::size_t>& indices ) const { std::size_t index = 0; for(std::size_t i=0; i!=elements_in_dimension.size(); ++i) { index += ( indices[i] * elements_in_dimension[i] ); } return data[ index ]; } T& operator()( const std::vector<std::size_t>& indices ) { std::size_t index = 0; for(std::size_t i=0; i!=elements_in_dimension.size(); ++i) { index += ( indices[i] * elements_in_dimension[i] ); } return data[ index ]; } }; int main() { std::vector<std::size_t> decl; // In C++11 geht das natuerlich besser. decl.push_back( 3 ); decl.push_back( 4 ); decl.push_back( 5 ); decl.push_back( 6 ); vector_nd<int> ar( decl ); // Bedeutet int ar[3][4][5][6] std::vector<std::size_t> indices; // In C++11 geht das natuerlich besser. indices.push_back( 2 ); indices.push_back( 3 ); indices.push_back( 4 ); indices.push_back( 5 ); std::cout << ar( indices ) << '\n'; // Bedeutet: cout << ar[2][3][4][5] und muss 359 ausgeben. ar( indices ) = 987; std::cout << ar( indices ) << '\n'; // Bedeutet: cout << ar[2][3][4][5] und muss 987 ausgeben. }
Kannst ja mal ausprobieren und mir dann sagen obs geht