Variadic Function ohne Parameteranzahl
-
Wurstinator schrieb:
Hallo,
der Titel verrät ja eigentlich schon ziemlich genau, was ich suche.
Gibt es die Möglichkeit, Funktionen mit variabler Parameteranzahl zu nutzen ohne die Anzahl dieser zu kennen?Ja, die Möglichkeit gibt es. Ist aber vielleicht nicht das was du suchst. Verrate uns lieber was du erreichen willst, statt nach der Methode zu fragen wie du es erreichen zu können glaubst.
-
@ Nexus: Ich weigere mich aber, C++0x zu nutzen, bis es der Standard ist

@ pumuckl: Eine Vektor-Klasse mit beliebig vielen Dimensionen. Die soll dann z.B. Vector<3> heißen. Beim Konstruktor soll man minimal 0 und maximal so viele Parameter angeben, wie es Dimensionen gibt. Der Rest wird dann mit einem Standardwert (z.B. 0) initialisiert.
Vector<3> v(1.0, 2.0); // <- soll klappen
-
Varidatisch Parameter gibt es auch aber die sind nicht typsicher...
-
Wurstinator schrieb:
Vector<3> v(1.0, 2.0); // <- soll klappenEs ist zwar nicht ganz das von dir gewünschte, aber hast du dir mal Boost-Assignment angeschaut?
-
Wurstinator schrieb:
@ pumuckl: Eine Vektor-Klasse mit beliebig vielen Dimensionen.
Meinst du Dimensionen oder Elemente? Nur dass wir von Gleichen reden. Ein vector mit 3 Dimensionen hätte z.B. 3 Längen/Ausdehnungen, also z.B. 8x14x22 Elemente. Ein vector mit 3 Elementen hat eben 3 Elemente. Das was du da skizzierst sieht eher nach letzterem aus, zumindest verstehe ich sonst den Konstruktoraufruf nicht.
Da du Vector<3> schreibst, also ein Template, nehme ich an, dass du die Größe (d.h. die Anzahl der Elemente) zur Compilezeit festnageln möchtest. Das spräche dann für std::array (C++0x-Standardbibliothek) bzw. std::tr1::array (C++ TR1) bzw. boost::array.
Das Ganze gewürzt mit boost::assign oder ggf. initializer-Listen in C++0x
-
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.