Variadic Function ohne Parameteranzahl
-
pumuckl schrieb:
Ein vector mit 3 Dimensionen hätte z.B. 3 Längen/Ausdehnungen, also z.B. 8x14x22 Elemente.
Ein dreidimensionaler Vektor ist für mich (x,y,z), also ein Vektor mit drei Komponenten. Die Dimension des Vektorraums ist 3. Zumindest falls wir von mathematischen Vektoren sprechen...
-
Ja, ich meinte mathematische Vektoren.
@ asc: Ich werds mir mal ansehen, danke.
edit: Entweder hab ich das falsch verstanden oder du hast mich (auch) falsch verstanden und dachtest, ich meine Vektoren-Listen.
-
Boost.Assign verwendet im Prinzip folgende Technik:
#include <algorithm> template <unsigned int N> struct Vector { int values[N]; Vector<N+1> operator() (int value) const { Vector<N+1> v; std::copy(values, values+N, v.values); v.values[N] = value; return v; } }; Vector<1> MakeVector(int value) { Vector<1> v; v.values[0] = value; return v; } int main() { Vector<4> x = MakeVector(4)(5)(7)(8); }Hier kopierst du natürlich unnötig viel. Kapselung ist auch nicht optimal, da man auf einem fertigen Vektor-Objekt immer noch
operator()aufrufen kann. Aber das Grundprinzip sollte verständlich werden...
-
Aber wenn ich das richtig verstehe, wird am Ende doch ein Vektor<N> zurückgegeben, wobei N die Anzahl der Parameter ist.
Vector<5> x = MakeVector(4)(5)(7)(8); // Fehler?
-
Ja, sollte einen Fehler ergeben weil ein
Vector<5>ein komplett anderer Typ ist alsVector<4>.
-
Das meinte ich ja.
Somit löst das eben genau nicht das, was ich erreichen will
-
Man kann aber mit einem impliziten Konvertierungsoperator das Verhalten verändern...
-
Wurstinator schrieb:
Das meinte ich ja.
Somit löst das eben genau nicht das, was ich erreichen willIch sagte ja, das Codebeispiel solle nur das Prinzip verdeutlichen. Wenn du rumbastelst, kannst du das beliebig konfigurieren und optimieren.
-
Wie verwende ich denn implizite Konvertierung mit Templates?
-
// Konstruktor-Definition ausserhalb der Klasse template <typename N> // Templateparameter der Klasse template <typename M> // Templateparameter der Funktion Vector<N>::Vector(const Vector<M>& smallerVector) { static_assert(M < N); // nicht <=, für == ist der Kopierkonstruktor // ... }Aber wenn du das wirklich so durchziehen willst und Performance eine Rolle spielt, solltest du einiges optimieren. Oder gleich Boost.Assign verwenden...
-
Ich würde jetzt gerne, neben der variablen Dimensionsgröße, auch noch den Typ für die Werte variabel machen.
Das klappt nicht:template<unsigned int DIM, class VTYPE=double> Vektor<1, VTYPE> Vektor::MakeVektor(VTYPE value) { Vektor<1, VTYPE> i; i[0] = value; return i; }error: 'template<unsigned int DIM, class VTYPE> class Vektor' used without template parameters|
error: default template arguments may not be used in function templates|Hat da noch jemand einen Rat für mich?
Ich bedanke mich aber schon für die bisherige Hilfe.Oder gleich Boost.Assign verwenden...
Ich dachte, Boost.Assign ist für Listen?
-
template<unsigned int DIM, class VTYPE> Vektor<1, VTYPE> Vektor<DIM, VTYPE>::MakeVektor(VTYPE value) //Unbekannter Typ lieber als Referenz auf const übergeben { Vektor<1, VTYPE> i; i[0] = value; return i; }EDIT: Wieso ist
MakeVektoreine Methode und keine freie Funktion? Und bei der Implementierung gibt man keine Default-Parameter an (bei Funktionen sowie bei Templates).
-
Ich habe schon mal so etwas hier gebaut:
template<class T, int Dim> struct point { T coeffs[Dim]; T const& operator[](int idx) const {return coeffs[idx];} T & operator[](int idx) {return coeffs[idx];} }; template<class Iter> inline void assign(Iter) {} template<class Iter, class Arg, class...More> inline void assign(Iter ptr, Arg&& arg, More&&... more) { *ptr = std::forward<Arg>(arg); ++ptr; assign(ptr,std::forward<More>(more)...); } template<class T, class...Args> point<T,sizeof...(Args)> make_point(Args&&...args) { point<T,sizeof...(Args)> result; assign(result.coeffs+0,std::forward<Args>(args)...); return result; } int main() { point<int,3> p = {{11,22,33}}; // Listen-Initialisierung klappt sogar in C++98 // da es sich um einen Aggregat-Typen handelt. auto q = make_point<double>(1.618,2.718,3.142); }(Warnung1: Dies ist einfach so runtergetippt ohne zu testen)
(Warnung2: Dies ist C++11 Code)
-
Wieso ist MakeVektor eine Methode und keine freie Funktion?
Weil Funktionen keine default-Parameter bei Templates haben können.
@ krümelkacker: Manches davon versteh ich leider nicht und ich bin um diese Uhrzeit auch nicht mehr wild darauf, mir die ganzen Befehle zusammenzusuchen

Aber danke, dass du mich an die const-Correctness erinnert hast. Die hab ich bei mir vergessen.Also, meine Klasse ist jetzt fertig. Falls jemand Lust hat, kann er ja mal drüberlesen und mir gegebenenfalls Tipps geben.
Ansonsten bedanke ich mich erneut und verziehe mich
#ifndef VEKTOR_HPP_INCLUDED #define VEKTOR_HPP_INCLUDED #include <stdarg.h> #include <string.h> #include <iostream> using namespace std; template<unsigned int DIM, class VTYPE=double> class Vektor; template<unsigned int DIM, class VTYPE> class Vektor { template<unsigned int friendDIM, class friendVTYPE> friend class Vektor; public: // Constructors Vektor() {}; template<class any> Vektor(any* x, ...); Vektor(VTYPE vals[]); template<unsigned int N> Vektor(const Vektor<N, VTYPE>& other); // Operators template<unsigned int N> Vektor<DIM, VTYPE> operator=(Vektor<N, VTYPE> other); Vektor<DIM, VTYPE> operator=(VTYPE vals[]); Vektor<DIM+1, VTYPE> operator()(VTYPE value) const; VTYPE& operator[](unsigned int index); const VTYPE& operator[](unsigned int index) const; // static "MakeVector" function static Vektor<0u, VTYPE> MakeVektor(); static Vektor<1u, VTYPE> MakeVektor(const VTYPE& value); protected: VTYPE values[DIM]; }; template<unsigned int DIM, class VTYPE> template<class any> Vektor<DIM, VTYPE>::Vektor(any* x, ...) { va_list args; va_start(args, x); for (unsigned int n = 0; n < DIM; n++) values[n] = va_arg(args, VTYPE); va_end(args); } template<unsigned int DIM, class VTYPE> Vektor<DIM, VTYPE>::Vektor(VTYPE vals[]) { memcpy(values, vals, sizeof(vals) * sizeof(VTYPE)); } template<unsigned int DIM, class VTYPE> template<unsigned int N> Vektor<DIM, VTYPE>::Vektor(const Vektor<N, VTYPE>& other) { memcpy(values, other.values, sizeof(other.values)); } template<unsigned int DIM, class VTYPE> template<unsigned int N> Vektor<DIM, VTYPE> Vektor<DIM, VTYPE>::operator=(Vektor<N, VTYPE> other) { memcpy(values, other.values, sizeof(other.values)); return *this; } template<unsigned int DIM, class VTYPE> Vektor<DIM, VTYPE> Vektor<DIM, VTYPE>::operator=(VTYPE vals[]) { memcpy(values, vals, sizeof(vals) * sizeof(VTYPE)); return *this; } template<unsigned int DIM, class VTYPE> Vektor<DIM+1, VTYPE> Vektor<DIM, VTYPE>::operator()(VTYPE value) const { Vektor<DIM+1, VTYPE> i(*this); i[DIM] = value; return i; } template<unsigned int DIM, class VTYPE> VTYPE& Vektor<DIM, VTYPE>::operator[](unsigned int index) { return values[index]; } template<unsigned int DIM, class VTYPE> const VTYPE& Vektor<DIM, VTYPE>::operator[](unsigned int index) const { return values[index]; } template<unsigned int DIM, class VTYPE> Vektor<0u, VTYPE> Vektor<DIM, VTYPE>::MakeVektor() { Vektor<0u, VTYPE> i; return i; } template<unsigned int DIM, class VTYPE> Vektor<1u, VTYPE> Vektor<DIM, VTYPE>::MakeVektor(const VTYPE& value) { Vektor<1u, VTYPE> i; i[0] = value; return i; } #endif // VEKTOR_HPP_INCLUDED
-
Mach das Array
valuesdochprivate. Klasse die vonVektorerben können darauf mit dem Feldoperator zugreifen. Und die beiden Zeilen 4 & 5 sind nicht standardkonform.
-
Mach das Array values doch private. Klasse die von Vektor erben können darauf mit dem Feldoperator zugreifen.
Schon klar, aber solange ich die Daten nicht geheim halten will, kann ich sie ja auch zugänglich machen. z.B. für memcpy braucht man ja den Array direkt.
Und die beiden Zeilen 4 & 5 sind nicht standardkonform.
Die beiden includes?

Was soll ich denn dann nehmen?
-
Wurstinator schrieb:
für memcpy braucht man ja den Array direkt.
Das kann man auch mit einer
for-Schleife machen.Wurstinator schrieb:
Was soll ich denn dann nehmen?
#include <cstdarg> #include <cstring>
-
Wurstinator schrieb:
Und die beiden Zeilen 4 & 5 sind nicht standardkonform.
Die beiden includes?

Was soll ich denn dann nehmen?Die C++ Versionen davon: <cstdarg> und <cstring>.
Ansonsten: Deine memcpy()-Aufrufe sind (a) schon für sich fehlerhaft (sizeof(vals) liefert alleine schon die benötigte Größe des Arrays in Byte), (b) katastrophal, wenn jemand das Template mit einer eigenen Numerik-Klasse verwenden will und (c) zumindest teilweise unnötig (das Kopieren kannst du bedenkenlos den compiler-generierten Methoden überlassen).
-
Ach Mist, ich habs verwechselt und dachte cstring/cstdarg wären die C-Header

@ CStoll: Bei diesem Konstruktor:
template<unsigned int DIM, class VTYPE> Vektor<DIM, VTYPE>::Vektor(VTYPE vals[]) { memcpy(values, vals, sizeof(vals) * sizeof(VTYPE)); }wird aber nicht richtig kopiert, wenn ich nur sizeof(vals) nehme.
Und zu welchen Problemen kann es mit einer eigenen Numerik-Klasse kommen? Weil der (Copy-)Konstruktor dann nicht aufgerufen wird?
-
Wurstinator schrieb:
Ach Mist, ich habs verwechselt und dachte cstring/cstdarg wären die C-Header

@ CStoll: Bei diesem Konstruktor:
template<unsigned int DIM, class VTYPE> Vektor<DIM, VTYPE>::Vektor(VTYPE vals[]) { memcpy(values, vals, sizeof(vals) * sizeof(VTYPE)); }wird aber nicht richtig kopiert, wenn ich nur sizeof(vals) nehme.
An der Stelle kopierst du auch mit der Konstruktion die falsche Anzahl. Korrekter wäre dort
DIM*sizeof(VTYPE)odersizeof(values)Und zu welchen Problemen kann es mit einer eigenen Numerik-Klasse kommen? Weil der (Copy-)Konstruktor dann nicht aufgerufen wird?
Genau so sieht's aus. Du brauchst dir nur mal eine BigInt-Klasse vorstellen, die ihren Wert in einem dynamisch verwalteten Array verstaut. Dann kopierst du per memcpy() die Innereien der Klasse und hast plötzlich zwei Objekte die beide der Meinung sind, sie hätten exklusiven Zugriff auf die dynamischen Daten.
(und gerade im Umgang mit Templates kann es schneller als erwartet passieren, daß so ein Fall eintritt)