Funktionen mit variierender Argumentenanzahl
-
Ich stehe garde total aufm schlauch.
Kann mir jemand bitte einen kurzen Bsp Code posten in dem man per cin einen Wert
(sting oder integer) eingibt und dann mittels dieses Wertes nach übereinstimmungen mit einem vector inhalt gesucht wird. Wenn einer gefunden wurde, soll die "Platznummer" des Objekts im vector ausgegeben werden soll.Die Objekte in dem vector sollen Objekte mit folgendem Typ sein:
class Test { public: int z; stirng a; string b; }Danke
-
struct Test { int a; string b; string c; }; bool operator==(const Test& rhs, const Test& lhs) { return (rhs.a == lhs.a) && (rhs.b == lhs.b) && (rhs.c == lhs.c); } bool operator!=(const Test& rhs, const Test& lhs) { return !(rhs == lhs); } int main() { // Vektor erstellen Test arr[] = { {1, "Wurst", "Kaese"} , {4, "Banane", "Brot"} , {9000, "Vegetarier", "Karotte"} }; vector<Test> vec(arr, arr + sizeof(arr) / sizeof(Test)); // Einlesen Test temp; cin >> temp.a >> temp.b >> temp.c; cout << endl; // Iterator finden vector<Test>::iterator iter = find(vec.begin(), vec.end(), temp); // Ausgabe if (iter == vec.end()) cout << "Element nicht gefunden." << endl; else { vector<Test>::size_type pos = iter - vec.begin(); cout << "Element an Position " << pos << " gefunden." << endl; } return 0; }
-
Hi, vieleicht kannst du dir hiermit ja etwas brauchbares basteln.
void search(int count, ...) { va_list l; va_start(l, count); for (int i = 0; i < count; ++i) { char *str = va_arg(l, char*); std::cout << "Str " << i << " : " << str << std::endl; } va_end(l); }search(3, "Test", "TdA", "OJ"); search(2, "Test2", "TdAasd");Gruß, Daniel
-
Lest mal seinen Code und überlegt mal, anstatt Müll zu antworten.
-
Das problem ist doch das der Compiler nicht erkennen kann ob der übergebene String jetzt für a oder für t übergeben wird.Die Funktion wäre nicht eindeutig da t und a beides Strings sind.
Meiner Meinung kann man das nur lösen indem man den Funktionnamen ändern und es so schreibt
void search_t(int z, string t) {search(z, t, "Default für a");} void search_a(int z, string a) {search(z, "Default für t", a);} void search(int z) {search(z, "Default für t", "Default für a");} void search(int z,string t,string a){...}
-
Daniel_S schrieb:
Das problem ist doch das der Compiler nicht erkennen kann ob der übergebene String jetzt für a oder für t übergeben wird.Die Funktion wäre nicht eindeutig da t und a beides Strings sind.
Meiner Meinung kann man das nur lösen indem man den Funktionnamen ändern und es so schreibt
void search_t(int z, string t) {search(z, t, "Default für a");} void search_a(int z, string a) {search(z, "Default für t", a);} void search(int z) {search(z, "Default für t", "Default für a");} void search(int z,string t,string a){...}Falsch. Ich empfehle dir das Buch "Effektiv C++ programmieren" von Scott Meyers.
Scott erklärt in diesem Buch, dass man dafür Enums (für eine abzählbare Menge von Eingabewerten, etwa Wochentage) oder eigene Typen dafür verwendet.also etwa sowas:
class Autor { string name; bool is_set; Autor(const char * name) : name(name), bool(name) {} bool isset() const { return is_set; } const string& name() const { return name; } }; class Titel{ //... analog zu Autor }; class ISBN{ //... }; entry_type suche(ISBN i, Autor a, Titel t); int main() { entry_type result = suche(ISBN(0), Autor("Scott Meyers"), Titel(0)); std::cout << result << std::endl; }Sowas in etwa. Die C-String sind zwar nicht schön, aber man kriegt über den Nullzeiger die Optionalität geschenkt - string* sollte auch gehen, ist aber umständlicher in der Benutzung.
-
bmario_ schrieb:
Daniel_S schrieb:
Das problem ist doch das der Compiler nicht erkennen kann ob der übergebene String jetzt für a oder für t übergeben wird.Die Funktion wäre nicht eindeutig da t und a beides Strings sind.
Meiner Meinung kann man das nur lösen indem man den Funktionnamen ändern und es so schreibt
void search_t(int z, string t) {search(z, t, "Default für a");} void search_a(int z, string a) {search(z, "Default für t", a);} void search(int z) {search(z, "Default für t", "Default für a");} void search(int z,string t,string a){...}Falsch. Ich empfehle dir das Buch "Effektiv C++ programmieren" von Scott Meyers.
Scott erklärt in diesem Buch, dass man dafür Enums (für eine abzählbare Menge von Eingabewerten, etwa Wochentage) oder eigene Typen dafür verwendet.also etwa sowas:
class Autor { string name; bool is_set; Autor(const char * name) : name(name), bool(name) {} bool isset() const { return is_set; } const string& name() const { return name; } }; class Titel{ //... analog zu Autor }; class ISBN{ //... }; entry_type suche(ISBN i, Autor a, Titel t); int main() { entry_type result = suche(ISBN(0), Autor("Scott Meyers"), Titel(0)); std::cout << result << std::endl; }Echt? Machst du eine extra Klasse für Name, Vorname, Straße, Benutzername, Titel, Nachrichtentext, X-Koordinate, Y-Koordinate, Autoname, Schiffname usw...
-
wooooaoaw schrieb:
Echt? Machst du eine extra Klasse für Name, Vorname, Straße, Benutzername, Titel, Nachrichtentext, X-Koordinate, Y-Koordinate, Autoname, Schiffname usw...
Finde ich auch übertrieben. Man könnte es sich für spezielle Formate wie ISBN-Nummer überlegen, aber für die meisten Eigenschaften würde ich
std::stringnehmen.Die Alternative eine Klasse mit allen Eigenschaften.
struct Buch { Buch(); // setzt Default-Werte std::string Titel; std::string Autor; ... }; int main() { Buch b; b.Titel = "Effective C++"; b.Autor = "Scott Meyers"; Suche(b); }Natürlich kann man hier noch stundenlang rumwerkeln und z.B. mit Set/Get kapseln, Named Constructor Idiom für schnelle temporäre Objekte anwenden oder sogar mehrere Argumentreihenfolgen erlauben. Aber ich bezweifle, dass sich der Aufwand lohnt.
-
wooooaoaw schrieb:
bmario_ schrieb:
Daniel_S schrieb:
Das problem ist doch das der Compiler nicht erkennen kann ob der übergebene String jetzt für a oder für t übergeben wird.Die Funktion wäre nicht eindeutig da t und a beides Strings sind.
Meiner Meinung kann man das nur lösen indem man den Funktionnamen ändern und es so schreibt
void search_t(int z, string t) {search(z, t, "Default für a");} void search_a(int z, string a) {search(z, "Default für t", a);} void search(int z) {search(z, "Default für t", "Default für a");} void search(int z,string t,string a){...}Falsch. Ich empfehle dir das Buch "Effektiv C++ programmieren" von Scott Meyers.
Scott erklärt in diesem Buch, dass man dafür Enums (für eine abzählbare Menge von Eingabewerten, etwa Wochentage) oder eigene Typen dafür verwendet.also etwa sowas:
class Autor { string name; bool is_set; Autor(const char * name) : name(name), bool(name) {} bool isset() const { return is_set; } const string& name() const { return name; } }; class Titel{ //... analog zu Autor }; class ISBN{ //... }; entry_type suche(ISBN i, Autor a, Titel t); int main() { entry_type result = suche(ISBN(0), Autor("Scott Meyers"), Titel(0)); std::cout << result << std::endl; }Echt? Machst du eine extra Klasse für Name, Vorname, Straße, Benutzername, Titel, Nachrichtentext, X-Koordinate, Y-Koordinate, Autoname, Schiffname usw...
Dort wo es sinnvoll ist

Ist sicher nicht überall sinnvoll. Scott Meyers hat sich da mit dem Datum aber ein sehr gutes Beispiel gesucht. Angenommen du schreibst eine Klasse, die ein Datum kapselt. Dann wäre der Konstruktor schnell aufgeschrieben:
Date(int day, int month, int year);Jetzt stell dir vor, ein Ami benutzt die Klasse für Weihnachten:
Date xmas = Date(12,24,2011);Okay, das kannst du mit assert() oder ähnlichem Abfangen, aber was ist mit dem 6.1.
Date heiligeDreiKoenige = Date(1,6,2012);Rumms! Nun wird das Weihnachtszeugs zum Kindertag weggeräumt

In diesem Speziellen Fall sind Klassen geeignet um ein fehlerhaftes Benutzen der Klasse schon beim kompilieren zu entdecken.
Date(Day d, Month m, Year y);(Achtung: explicit Konstruktor, hab ich oben vergessen)
Der selbe Ami kann nun folgendes nicht mehr kompilieren:
Date nikolaus = Date(Month(12), Day(6), Year(2011));Damit haben wir einen Logikfehler bereits beim Kompileren abgefangen. Super!
-
Und um nicht für alles eine separate Klasse zu schreiben, kannst du z.B. sowas verwenden:
template <typename T, typename TypeTag = void> class Value { public: Value() : mValue() { } explicit Value(T value) : mValue(value) { } T Get() const { return mValue; } private: T mValue; };Der zweite Template-Parameter dient zur typsicheren Unterscheidung bei ähnlichen Typen. Beispiel:
namespace Tags { struct Day; struct Month; struct Year; } typedef Value<int, Tags::Day> Day; typedef Value<int, Tags::Month> Month; typedef Value<int, Tags::Year> Year;
-
Ja Nexus, dass ist definitiv praktisch

Die Grundidee bleibt aber die selbe. Ein eigener Typ für semantisch verschiedene Eingabewerte. Man muss das natürlich nicht immer so machen, aber gerade für Schnittstellen bietet sich diese zusätzliche Sicherheit an. Man kann das ganze auch weitertreiben, etwa Day in Abhängigkeit zu Month bringen (30 vs 31 Tage) oder gar noch Year (man denke nur Schaltjahre). Aber dies sollte man im Einzelfall überprüfen.