Designproblem Vector3D, Vector4D oder Vector<int Dimensions>?
-
Mrr, jetzt hab ich aber doch eine sich anschließende Frage.
Den neuen Vector brauche ich, weil ich aus Matrizen (die allerdings immer 4x4 sind) gerne Spalten rauskopieren möchte, diese dann z.B. mit einem Skalar multiplizieren will und wiederum zu einer anderen Spalte meiner Matrix addieren möchte.
Der Vorteil von meinem undynamischen 3D-Vector war die Übersichtlichkeit bei der Verwendung. GetX() und GetY() waren klar. Danach habe ich Get(0) oder Get(1). Eine entsprechende Templatefunktion ginge, um das zu lösen. Aber ich habe auch ein anderes Problem, der ctor.Bei einem dynamischen Vector muss ich ja mit Arrays im ctor arbeiten, Parameterlisten kann ich ja nicht dynamisch erstellen, auch in C++0x funktioniert das ja nur für Template-Parameterlisten, oder? Und zur Zeit kann ich ja nicht sagen:
typedef Vector<float, 3> 3DVector; 3DVector v({1,2,3});Darum habe ich mir folgende, globale Funktion gebastelt:
template<typename C> Vector<C, 3> Vector3D(C c1, C c2, C c3) { C components[] = {c1, c2, c3}; return Vector<C, 3>(components); }Das funktioniert zwar, ist aber ggü. meiner alten Version trotzdem unschöner. Zudem nutze ich ein globales typedef für einen fest typisierten Vector mit float, da der (zur Zeit!) hauptsächlich genutzt wird. Das sieht also etwa so aus, dass ich eine Global-Datei habe:
namespace Engine { typedef Vector<float, 3> CommonVector; }Wenn ich jetzt obige Methode nutzen möchte, macht das die Benutzung lang:
using namespace Engine;; typedef CommonVector::ComponentType CommonComponentType; CommonVector v(Vector3D<CommonComponentType>(1.f, 2.f, 3.f));Na ja... Geht alles, aber vorher war's natürlich schon leichter.
Gut, letztendlich ist eigentlich die Frage, ob es nicht einfacher wäre, wirklich diese von Dir angesprochene Tipparbeit zu machen. Wahrscheinlich machen Templates für diesen Teil keinen Sinn mehr. Eigentlich brauche ich zur Zeit nur 3D- und 4D-Vektoren (wobei ich mir Fälle vorstellen kann, wo es später mehr werden und die meisten Operationen sind natürlich gleich). Also könnte ich beide Vektoren implementieren, auch wenn die sich zu 90% ähneln.
Oder ich vererbe. Das erscheint nur nicht "üblich", eigentlich hätte ich für mein Problem jetzt gedacht, statische Polymorphie trifft mein Problem besser. Aber solange ich nichts virtual mache, bleibt der angeleitete Typ auch POD, oder? Das wäre wichtig. Und da gibt's im neuen Standard ja auch eine weniger restriktive Definition, nützt mir aber erstmal nix.
Hm... Irgendwelche Ideen?
Edit:
Mittlerweile glaube ich, Templates oder Vererbung zu nehmen ist Overdesigning. Matrix4x4 brauche ich hauptsächlich, Vector3D und Vector4D... also mache ich jetzt wohl genau diese Klassen. Und nutze nur noch einen template-Parameter für den Typ.
Falls irgendwer Ideen/Einwände/was auch immer hat, freue ich mich natürlich trotzdem sehr!
-
Eisflamme schrieb:
Mrr, jetzt hab ich aber doch eine sich anschließende Frage.
Ist dir kalt, Eisflamme?

Eisflamme schrieb:
Mittlerweile glaube ich, Templates oder Vererbung zu nehmen ist Overdesigning. Matrix4x4 brauche ich hauptsächlich, Vector3D und Vector4D... also mache ich jetzt wohl genau diese Klassen. Und nutze nur noch einen template-Parameter für den Typ.
Falls irgendwer Ideen/Einwände/was auch immer hat, freue ich mich natürlich trotzdem sehr!Halte ich für den einzig richtigen Weg

Falls jemand Vektoren mit anderen Grössen haben möchte, dann gäbe es ja nochstd::valarray.Grüssli
-
Hi,
Super, vielen Dank! Freut mich, das zu hören!
valarray hat aber *, + nicht überladen und da mir die Implementierung, nicht bekannt ist, weiß ich nicht ob sizeof(valarray) (kann man das überhaupt so schreiben? sonst sei valarray ein Synonym für eine valarray-Instanz, auch wenn das nicht geht :P) == Dimensions * sizeof(ComponentType) ist, was ich aber brauche, weil ich die Daten u.U. genau so weitergebe.

Übrigens hab ich nicht brr sondern mrr gesagt

Bis demnächst!
-
Eisflamme schrieb:
valarray hat aber *, + nicht überladen ...
Hmmm, lass mich mal schnell meine Liste durchschauen...
http://www.cplusplus.com/reference/std/valarray/valarray/operators/... also ich sehe da einen operator*,+, usw.

Eisflamme schrieb:
... und da mir die Implementierung, nicht bekannt ist, weiß ich nicht ob sizeof(valarray) (kann man das überhaupt so schreiben? sonst sei valarray ein Synonym für eine valarray-Instanz, auch wenn das nicht geht :P) == Dimensions * sizeof(ComponentType) ist, was ich aber brauche, weil ich die Daten u.U. genau so weitergebe.

Ich glaube nicht, da
std::valarrayeine dynamische Grösse haben kann, wie zum Beispielstd::vector.std::valarrayist, bzw. sollte, einfach darauf optimiert sein, auf seine Elemente mathematische Funktionen aufzurufen. Darf ich fragen, wieso du diese Voraussetzung haben musst?sizeof(std::valarray)ist übrigens absolut erlaubt, wie auch zum Beispielsizeof(ComponentType)geht
Eisflamme schrieb:
Übrigens hab ich nicht brr sondern mrr gesagt

Die Leute frieren zum Teil ganz unterschiedlich. Es gibt sogar welche, die so ein klapper Geräusch mit den Zähnen machen

Ehm, aber was war dann dieses "Mrr"? Ich kenne Wesen, welche so ein Geräusch machen, wenn sie befriedigt werden ...
Grüssli
-
Mittels templates und Vererbung kannst du dir recht komfortabel eine Arrayklasse bauen, die beliebig viele Dimensionen unterstützt:
#include <vector> template<typename T, unsigned int D> class ArrayBase { protected: std::vector<T> Elements_; unsigned int Extents_[D]; public: ArrayBase() { } // Ausdehnung zurückgeben std::size_type get_extent( unsigned int Dim ) const { assert( Dim < D ); return Extents_[Dim]; } }; template<typename T> class Array1D : public ArrayBase<T,1> { public: Array1D() { } void resize( std::size_type Dim ) { // Vektorgröße setzen Elements_.resize( Dim ); // Ausdehnung setzen Extents_[0] = Dim; } T& operator()( std::size_type Index ) { return Elements_[Index]; } const T& operator()( std::size_type Index ) const { return Elements_[Index]; } }; template<typename T> class Array2D : public ArrayBase<T,2> { public: Array2D(); void resize( unsigned int Dim1, unsigned int Dim2 ) { // Vektorgröße und Ausdehnung setzen Elements_.resize( Dim1 * Dim2 ); Extents_[0] = Dim1; Extents_[1] = Dim2; } T& operator()( std::size_type i1, std::size_type i2 ) { return Elements_[i2 * Extents_[0] + i1]; } const T& operator()( std::size_type i1, std::size_type i2 ) const { return Elements_[i2 * Extents_[0] + i1]; } }Das ist nur ein Minimalbeispiel, durch die Implementation von 3 Funktionen lässt sich eine Arrayklasse für eine andere Anzahl von Dimensionen erzeugen. Die Ergänzung der Funktionen empty()/size()/clear() ist trivial, über Iteratorsupport kann man sich Gedanken machen (z.B. Zeilen-/Spalteniteratoren für 2D Arrays).
-
Mein Vector Template sind im wesentlichen so aus wie std::array. Alles andere mach ich mit nichtmember Funktionen. So auch
auto v3 = MakeVector(1.0, 2.0, 3.0);Den Typparameter musst du da bei eindeutigen Typen nicht mit angeben, finde ich daher nicht viel umständlicher als
Vector<double, 3> v3(1.0, 2.0, 3.14);Wie bei std::array könnte man auch
Vector<double, 3> v3 = {1.0, 2.0, 3.14};Wenn der array öffentlich ist und kein Konstruktor definiert ist.
Die X, Y, Z Komfortfunktionen habe ich so:template<typename T, size_t Dim> T& Z(const Vector<T, Dim>& v) { static_assert(Vector<T, Dim>::Dimsension > 2); return v[2]; }Operatoren sind auch als nichtmember implementiert. Die Schleifen werden da übrigens bei kleinen Dimensionen von nem normalen Compiler wegoptimiert.
-
Hi,
Hm, also ist das Mischen von Templates und Klassen doch eine gute Moeglichkeit? Streng genommen brauch ich aber die Dynamik zur Zeit noch nicht. Was macht man da jetzt...

Dravere:
Ich wuerde die Vektoren hin und wieder als Array verwenden und an OpenGL geben, da darf natuerlich kein andres Zeug drin haengen. Hm... vll. geht das allerdings auch so nicht.brotbernd:
Ok, makevector ist ganz nett. Hin und wieder will ich einfach einen neu erstellten Vector einer Funktion uebergeben, da ist es laestig, wenn ich extra fuer jeden Vector eine neue Zeile brauche.Die Operatoren sind ausserhalb der Klasse definiert? Alle wie auch *= etc. oder andere unaere? Und gibt es einen Grund, wieso du () statt [] verwendest?
-
Eisflamme schrieb:
Streng genommen brauch ich aber die Dynamik zur Zeit noch nicht. Was macht man da jetzt...

Wenn die Dynamik nicht benötigt wird, dann implementiere sie auch nicht. Im allgemeinen gilt, umso dynamischer ein Programm sein soll, umso komplexer wird es und dadurch steigt die Wartungsproblematik.
Zudem schau dir die Implementierungen von DocShoe und brotbernd an und schau dir dann eine "normale" Vec2D oder Vec3D Klasse an. Was wirkt intuitiver?Man kann es mit Templates und Dynamik auch übertreiben.
Eisflamme schrieb:
Ich wuerde die Vektoren hin und wieder als Array verwenden und an OpenGL geben, da darf natuerlich kein andres Zeug drin haengen. Hm... vll. geht das allerdings auch so nicht.
Da musst du extrem aufpassen, dass du eine binäre Kompatibilität behälst. Also wahrscheinlich schon mal nur PODs. Somit keine Vererbung, kein Destruktor, keine non-POD Member, usw. usf.
Eisflamme schrieb:
Die Operatoren sind ausserhalb der Klasse definiert? Alle wie auch *= etc. oder andere unaere?
Meinst du bei
std::valarray? Da ist nur die Dokumentation verwirrend. Schau dir die Signaturen genauer an. Es gibt zwei Sektionen:
*** valarray member functions: ***
und
*** global functions: ***Eisflamme schrieb:
Und gibt es einen Grund, wieso du () statt [] verwendest?
Wenn du damit den Code von DocShoe meinst:
Man kann bei einemoperator[]nicht zwei Parameter übergeben.Allerdings ist sein Code sowieso etwas fraglich. Der geht doch völlig neben dem vorbei, was du eigentlich möchtest. Auch seine Bezeichnung ist verwirrend. Array1D ist ein Vektor mit beliebiger Grösse, Array2D ist eine Matrix mit beliebiger Grösse. Die Dimensionen sind keine Dimensionen.
Grüssli
-
Oh je, Asche über mein Haupt. Hab´ den Thread wieder mal nur überflogen, geglaubt verstanden zu haben, worum es geht und dann völlig am Thema vorbeigeredet.
-
Falls es keine selbstgebastelte Matrix-/Vektor-Implementierung sein muss oder man sich ein paar Anregungen holen will:
Grüße