Variable Parameterliste mit Objekten ?
-
hi,
ich könnte für eine Collection einen Konstruktor mit variabler Parameterliste gebrauchen. Nun meldet mr meine IDE aber, dass die Verwendung von va_list mit einem non-POD zu einem laufzeitfehler führt.
Kann man da irgendwie einen work-around machen? das wäre nämlich ein häßliches workaround wenn es nicht gehen würde.
Collection::Collection(int c, ...) { m_count = c; va_list vl; va_start(vl, c); m_member = new Set[c]; for(int i=0; i < c; i++) m_member[i] = va_arg(vl, Set); va_end(vl); }
-
Davon abgesehen das variable Parameterlisten kein gutes Design sind und eigentlich überall davon abgeraten wird: Warum nicht Pointer?
-
...und: Warum nicht Polymorphie ? Warum nicht vector ?
Gruß,
Simon2.
-
Fellhuhn schrieb:
Davon abgesehen das variable Parameterlisten kein gutes Design sind und eigentlich überall davon abgeraten wird: Warum nicht Pointer?
Versteh ich das richtig, Pointer auf Objekte wäre ok bzw (void
???in diesem speziellen fall fänd ich variable parameterliste eine durchaus schöne lösung

-
va_args sind nicht schön, da sie nicht gut mit dem typsystem von C++ zusammenpassen; ein objekt (das nicht pod ist) so zu übergeben ist undefiniertes verhalten.
die C++ lösung wären wohl variadic templates, aber die gibt es noch nicht.
-
Simon2 schrieb:
Warum nicht vector ?
Würde ich auch meinen. Man kann auch mehrere Konstruktoren bereitstellen, die verschiedene Containertypen annehmen.
-
Variante 1) Template ctor mit input-iterator-range:
class Collection { public: template <class InputIterator> Collection(InputIterator dataBegin, InputIterator dataEnd) { for (InputIterator it = dataBegin; it != dataEnd; ++it) Add(*it); } };Variante 2) Hilfs-Klasse:
class CollectionInitHelper { public: CollectionInitHelper(); CollectionInitHelper operator << (Foo* foo) const; // ... private: CollectionInitHelper(CollectionInitHelper const* previous, Foo* foo); }; class Collection ... // ... void Bar() { Collection c(CollectionInitHelper() << foo1 << foo2 << foo3 << foo4); }Variante 2 kann man mit templates noch schöner hinbekommen so dass man nicht mit Zeigern o.ä. rumhantieren muss, die Länge nicht durchzählen etc. Ist aber vermutlich Overkill. Meist sollte Variante 1 reichen.
Variante 3: auf den neuen C++ Standard warten.
-
soweit ich mich erinnern kann ist in C++ die Ellipse mit Klassen nicht definiert oder erzeugt unspezifiziertes Verhalten (Sutter schrieb da in einem der Exceptional Bücher was)
Eventuell ist auch boost::assign::list_of() für deine Geschichte von interesse:
http://www.boost.org/doc/libs/1_37_0/libs/assign/doc/index.html
-
hustbaer schrieb:
Variante 3: auf den neuen C++ Standard warten.
Variante 3b: Präprozessor-Magie:
#include <iostream> #include <vector> #include <boost/preprocessor/repetition/repeat.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> class Foo { public: Foo(int n_) : n(n_) { } int n; }; /* * Die eigentliche Funktion, mit Vector als Parameter */ void bar(std::vector<Foo> const & args) { for (std::vector<Foo>::const_iterator it = args.begin(); it != args.end(); ++it) { std::cout << it->n << std::endl; } } /* * Generiert Wrapper für bar() mit 1 bis 10 Parametern */ #define PP_PUSH_BACK(z, n, arg) args.push_back(arg ## n); #define PP_BAR(z, n, data) \ void bar(BOOST_PP_ENUM_PARAMS(n, Foo const & f)) { \ std::vector<Foo> args; \ BOOST_PP_REPEAT_ ## z(n, PP_PUSH_BACK, f) \ bar(args); \ } BOOST_PP_REPEAT_FROM_TO(1, 10, PP_BAR, ~) #undef PP_PUSH_BACK #undef PP_BAR int main() { // Aufruf mit Vector std::vector<Foo> v; v.push_back(Foo(4)); v.push_back(Foo(8)); v.push_back(Foo(15)); bar(v); // Aufruf mit Einzelwerten bar(Foo(16), Foo(23), Foo(42)); }Zugegeben, der Präprozessor-Code ist extrem kryptisch, aber den schreibt man ja auch nur einmal.

Das Ganze lohnt sich natürlich erst dann, wenn man die Funktion an vielen verschiedenen Stellen aufruft, jeweils mit unterschiedlicher Parameter-Anzahl.
-
usiko schrieb:
Fellhuhn schrieb:
Davon abgesehen das variable Parameterlisten kein gutes Design sind und eigentlich überall davon abgeraten wird: Warum nicht Pointer?
Versteh ich das richtig, Pointer auf Objekte wäre ok bzw (void
???in diesem speziellen fall fänd ich variable parameterliste eine durchaus schöne lösung

Ein Pointer ist ja (im Grunde) auch nur ein (unsigned) int und daher auch ein POD-Typ. Also kannst du in deiner variablen Parameterliste beliebige Pointer übergeben. Welche Typen die Pointer eigentlich haben musst du ja eh wissen, das ist ja der Ekel an Parameterlisten.
Aber wie schon reichlich erwähnt wurde hier: Mach es nicht.