Problem mit dem Umgang von variabler Anzahl von Argumenten
-
Hallo, ich bin neu hier und dies ist meine erste Frage hier.
Ich möchte folgendendes Codefragment von meinem Rot-Schwarz-Baum modifizieren:
template <typename type_administrate_data, typename type_key> class rb_node { public: type_key key; bool color; rb_node *parent_node; rb_node *left_node; rb_node *right_node; rb_node *prev_node; rb_node *next_node; type_administrate_data *data_ptr; //==================================================================== rb_node() { color = COLOR_RED; left_node = NULL; right_node = NULL; data_ptr = new type_administrate_data; } //==================================================================== ~rb_node() { delete data_ptr; } //==================================================================== };Und zwar so das über die Konstruktormethode eine beliebige Anzahl an Argumenten übergeben werden kann. Die Konstruktormethode umzubauen ist ja auch noch kein Problem. Innerhalb der Konstruktormethode sollen jedoch die variable Anzahl von Argumenten weitergegeben werden an den "nächsten Konstruktor", nähmlich an den in Programmzeile 19. Dabei ist ja zubeachten das
type_administrate_dataja eine Klasse jeglicher Art und somit mit ganz unterschiedlicher Konstruktormethode sein kann.
Bin im Moment soweit gekommen:
#include <iostream> using namespace std; #include <stdargs.h> template <typename type_administrate_data, typename type_key> class rb_node { public: type_key key; bool color; rb_node *parent_node; rb_node *left_node; rb_node *right_node; rb_node *prev_node; rb_node *next_node; type_administrate_data *data_ptr; //==================================================================== rb_node(int Anzahl, ... ) { va_list params; // Zugriffshandle für Parameter int intpar; // Parameterinhalt color = COLOR_RED; left_node = NULL; right_node = NULL; va_start(params, Anzahl); // Zugriff vorbereiten // Durchlaufe alle Parameter (steht in Anzahl) for (int i=0; i<Anzahl; i++) { intpar = va_arg(params, int); // hole den Parameter cout << intpar << endl; // zeige ihn an (einfach zur Verdeutlichung) } cout << "---" << endl; va_end(params); // Zugriff abschließen data_ptr = new type_administrate_data; // ??? Hier habe ich keinen Plan :-( ??? } //==================================================================== ~rb_node() { delete data_ptr; } //==================================================================== };Das übergeben und 'isolieren' der Argumente ist also nicht das Problem. Wie aber kann ich diese Argumente nun an den "nächsten" Konstruktor weitergeben? Geht das überhaupt. Oder ist das Syntaktisch von C++ her überhaupt nicht möglich?
Sage schon jetzt danke für eure Hilfe.
Grüße Fonso
-
Ich würde mich ganz schnell von variablen Argumentlisten in trennen, die passen nämlich nicht zu C++ (hier wurde das Thema gerade besprochen).
Warum möchtest du mehrere Argumente, was repräsentieren diese genau? Durch Operatorüberladung kannst du oft eine syntaktisch akzeptable Alternative wählen.
-
fonso schrieb:
template <typename type_administrate_data, typename type_key> class rb_node { public: type_key key; bool color; rb_node *parent_node; rb_node *left_node; rb_node *right_node; rb_node *prev_node; rb_node *next_node; type_administrate_data *data_ptr;Wofür ist prev_node und next_node?
Warum ist data_ptr ein Zeiger?fonso schrieb:
Und zwar so das über die Konstruktormethode eine beliebige Anzahl an Argumenten übergeben werden kann.
Wozu und was für Argumente denn?
fonso schrieb:
Die Konstruktormethode umzubauen ist ja auch noch kein Problem. Innerhalb der Konstruktormethode sollen jedoch die variable Anzahl von Argumenten weitergegeben werden an den "nächsten Konstruktor", nähmlich an den in Programmzeile 19. Dabei ist ja zubeachten das
type_administrate_dataja eine Klasse jeglicher Art und somit mit ganz unterschiedlicher Konstruktormethode sein kann.
Aha! Typischerweise regelt man das in der Standardbibliothek über einen Kopierkonstruktor des Werttyps. Siehe zB std::vector::push_back. Das Ding nimmt eine Referenz entgegen und konstruiert eine eigene Kopie des Arguments.
Du willst scheinbar das Objekt direkt in der Datenstruktur selbst konstruieren -- ohne Umweg über den Kopierkonstruktor. Ich muss Dich leider enttäuschen. Das geht in C++ nicht. Im Nachfolger, zur Zeit immer noch C++0x genannt, auch wenn das Jahr 2009 bald vorbei ist, werden viele Container emplace_*-Funktionen bekommen, die genau das machen, was Du willst. Parameter weiterleiten für Konstruktoren beliebiger Typen. Dazu werden zwei neue C++0x Sprachfeatures benutzt: Variadische Templates und Rvalue-Referenzen. Das sieht dann zB so aus:
template<typename T> class behaelter { T dings; public: template<typename... Args> explicit behaelter(Args && ... args) : dings( std::forward<Args>(args)... ) {} };Aber wie gesagt, in C++03 geht das nicht so elegant.
fonso schrieb:
Bin im Moment soweit gekommen:
...rb_node(int Anzahl, ... )Das übergeben und 'isolieren' der Argumente ist also nicht das Problem. Wie aber kann ich diese Argumente nun an den "nächsten" Konstruktor weitergeben? Geht das überhaupt. Oder ist das Syntaktisch von C++ her überhaupt nicht möglich?
Vergiss es. Du müsstest jeden Fall einzeln behandeln und selbst das funktioniert nicht perfekt:
template<typename T> class behaelter { T dings; public: behaelter() {} template<typename A> explicit behaelter(A & a) : dings( a ) {} template<typename A> explicit behaelter(A const& a) : dings( a ) {} template<typename A, typename B> explicit behaelter(A & a, B & b) : dings( a, b ) {} template<typename A, typename B> explicit behaelter(A const& a, B & b) : dings( a, b ) {} template<typename A, typename B> explicit behaelter(A & a, B const& b) : dings( a, b ) {} template<typename A, typename B> explicit behaelter(A const& a, B const& b) : dings( a, b ) {} };"Perfect forwarding" gibt es erst mit Variadischen Templates und Rvalue-Referenzen. Freue Dich auf C++0x.
Gruß,
SP
-
Hallo,
danke für die Antworten
Hallo Sebastian,
Mein Ziel war es einen Rot-Schwarzbaum zu programmieren wo kompromisslos auf performance getrimmt ist. Aber der Baum sollte auch die Eigenschaften von verketteten Listen aufweisen. Damit auch das "vor und rückwärtsblättern" performant ausgeführt werden kann wird einfach noch zusätzlich eine doppelverkettete Liste geführt.
Es gibt in meiner Rot-Schwarz-Baum-Klasse eine Methode wie folgt:
type_administrate_data *create_new_entry(const type_key &key)Diese Methode generiert ein neues Node im Rot-Schwarz-Baum mit angegebenem Key, innerhalb des Nodes wird dann in der Konstruktor-Methode eben eine Instanz des "Datenobjekts" angelegt welches dem Node und somit dem Key zugeordnet ist (sei das Datenobjekt ein Integer, float oder eben eine Klasse jeglicher Art). Die obige Methode gibt also einen Zeiger zurück auf die Instanz des Objektes welches eben im Nodekonstruktor angelegt wurde.
Meine Rot-Schwarz-Baum-Klasse ist so entworfen das der "Anwender" von dieser einfach die Methoden der Rot-Schwarz-Baum-Klasse anwendet und sich um die zu verwaltenden Datenobjekte hinsichtlich Speicherreservierung und Freigabe nicht weiter zu kümmern zu braucht, diese Aufgabe erledigt auch gleich meine Klasse. Liste nachfolgend mal einfach mal ein paar öffentlichen Methoden der Rot-Schwarz-Baum-Klasse auf, dann müsste klar werden was gemeint ist.
type_administrate_data *create_new_entry(const type_key &key) type_administrate_data *search_entry(const type_key &key) type_administrate_data *get_first_entry(register type_key &return_key) type_administrate_data *get_last_entry(register type_key &return_key) type_administrate_data *get_next_entry(register type_key &return_key) type_administrate_data *get_prev_entry(register type_key &return_key) bool delete_first_entry(register type_key &return_key) bool delete_last_entry(register type_key &return_key) bool delete_entry(const type_key &key) void delete_all_entrys() bool rename_all_keys_from_entrys(register const type_key &val_from_min_key, register const type_key &key_incrementation) bool rename_key_from_entry(register const type_key &old_key, register const type_key &new_key) rb_tree() ~rb_tree()Meine Idee ist es nun, das es einfach schön wäre wenn man die Argumente von dem Konstruktor von dem verwaltetem "Datenobjekt" (sorry weis nicht wie anders dazu sagen soll) einfach auch bei der Methode...
type_administrate_data *create_new_entry(const type_key &key)...gleich mitangeben könnte (und die Argumente müsste man ja "irgendwo" angeben wenn man eine Klasse verwalten will wo nur einen Konstruktor mit Argumenten hat). Meine Frage zielte also auf die "Vorarbeit" ab um dieses Ziel erreichen zu können...
Hoffe ich hab den Sachverhalt verständlich rübergebracht.
Grüße Fonso
-
Ach ja was ich vergessen habe...
das gesammte Klassenkonstrukt sieht in "Wirklichkeit" so aus...
template <typename type_administrate_data, typename type_key> class rb_tree { private: class rb_node { public: type_key key; bool color; rb_node *parent_node; rb_node *left_node; rb_node *right_node; rb_node *prev_node; rb_node *next_node; type_administrate_data *data_ptr; //================================================================ rb_node() { color = COLOR_RED; left_node = NULL; right_node = NULL; data_ptr = new type_administrate_data; } //================================================================ ~rb_node() { delete data_ptr; } //================================================================ }; // Hier Methoden von Rot-Schwarz-Baum-Klasse // ... // ... // ... };Einer der seltenen Fälle wo "Klasse in Klasse" definierung auch sinn macht...
Gruß Fonso