Variadic Function ohne Parameteranzahl
-
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)
-
non-POD + ellipse ist sowieso UB.
-
An der Stelle kopierst du auch mit der Konstruktion die falsche Anzahl. Korrekter wäre dort DIM*sizeof(VTYPE) oder sizeof(values)
Wieso ist es denn richtiger, wenn ich mehr Werte kopiere, als der Quellarray hat?
non-POD + ellipse ist sowieso UB.
Was heißt UB?
-
Wurstinator schrieb:
An der Stelle kopierst du auch mit der Konstruktion die falsche Anzahl. Korrekter wäre dort DIM*sizeof(VTYPE) oder sizeof(values)
Wieso ist es denn richtiger, wenn ich mehr Werte kopiere, als der Quellarray hat?
Auch wenn es sich gut tarnt, übergibst du dort kein Array, sondern nur einen Zeiger - und auf den angewendet gibt dir sizeof() keine praktisch verwertbare Angabe.
-
Wurstinator schrieb:
Was heißt UB?
Undefined behavior – undefiniertes Verhalten, also ein Bug der übelsten Sorte.
-
Auch wenn es sich gut tarnt, übergibst du dort kein Array, sondern nur einen Zeiger - und auf den angewendet gibt dir sizeof() keine praktisch verwertbare Angabe.
Hä? Du hast doch ein paar Beiträge vorher gesagt, sizeof(vals) wäre die Größe des Arrays (in Bytes).
Undefined behavior – undefiniertes Verhalten, also ein Bug der übelsten Sorte.
Und warum ist das in diesem Fall so? oO
-
Wurstinator schrieb:
Auch wenn es sich gut tarnt, übergibst du dort kein Array, sondern nur einen Zeiger - und auf den angewendet gibt dir sizeof() keine praktisch verwertbare Angabe.
Hä? Du hast doch ein paar Beiträge vorher gesagt, sizeof(vals) wäre die Größe des Arrays (in Bytes).
Da bin ich wohl mit deinem Bezeichnern durcheinandergekommen - sizeof() liefert die Größe des angegebenen Ausdrucks. Bei einem echten Array ist das dessen Gesamtgröße (Elementzahl*Elementgröße), bei einem Zeiger (inklusive "Array"-Parameter) idR 4 oder 8 je nach Betriebssystem.
-
Wurstinator schrieb:
Hä? Du hast doch ein paar Beiträge vorher gesagt, sizeof(vals) wäre die Größe des Arrays (in Bytes).
Zeiger und Array sind leicht unterschiedlich:
sizeof(Ptr)liefert den Speicher des Zeigers zurück (auch wenn er auf ein Array zeigt) undsizeof(Arr)liefert den Speicher eines Elementes mal die Anzahl Elemente.EDIT: Mal wieder zu lahm

-
Und was ist ein "echter" Array?
-
Wurstinator schrieb:
Und was ist ein "echter" Array?
int EchtesArray[15]; int* KeinEchtesArray = new int[15]; int* AuchKeinEchtesArray = EchtesArray;
-
Du hast ein "echtes" Array dort in der Hand, wo du es als Array definiert hast. Dazu gehört z.B. der Klassenmember
VTYPE values[DIM];. Dort weiß der Compiler noch, daß er ein Array hat (und wie groß es ist), also kann er auch damit umgehen.
-
unechte Zeiger? ganz ganz echte Arrays?
Es ist viel einfacher:
Zeiger, Arrays, Zeiger, Arrays... bitte nicht mit irgendwelchen Qualifikationen verwirren, die hier keinen Platz haben. Der Compiler macht ganz sicher nicht so feine Unterschiede.