Template Fehler
-
Hi!
ich benutze "Templates" nicht oft und habe daher einen Fehler, den ich zu beheben nicht in der Lage bin.
Folgender Programmcode:
#include <string> #include <iostream> using namespace std; template<class T> T getValue(string foo, int bar){ switch(bar){ case 1: return (int) 5; case 2: return (string) "lalala"; } } int main(void){ string qry1 = "foobar1"; string qry2 = "foobar2"; int res1 = getValue(qry1, 1); cout << res1 << endl; string res2 = getValue(qry2, 2); cout << res2 << endl; return 0; }Die Fehlerausgabe sagt, dass die Funktion "getValue" nicht gefunden wird.
template.cpp: In function ‘int main()’:
template.cpp:23: error: no matching function for call to ‘getValue(std::string&, int)’
template.cpp:27: error: no matching function for call to ‘getValue(std::string&, int)’ich wäre sehr dankbar, wenn mir jemand einen Tipp geben könnte.
viele Grüße
Sdy
-
Ein Template ist eine generische Schablone, in die der Compiler während des Kompilierens konkrete Typen einsetzt und daraus Code erzeugt.
Was du hier versuchst, kann nicht funktionieren, weil der Rückgabetyp erst während der Laufzeit des Programms ermittelt werden soll, wenn die Codeerzeugung schon vorbei ist.Du müsstest dein Konstrukt also so umbauen, dass der Compiler entscheiden kann, welchen Typ du willst.
-
hmm...verdammt!
kennst du eine andere methode, wie ich verschiedene werte aus einer funktion zurückgeben kann?! aber nicht sowas wie struct, in dem alle werte gelistet sind o.a..
Ansonsten bleibt mir ja nichts anderes übrig, als für jeden datentypen ne eigene funktion zu schreiben.
-
Registrierter Troll hat dir die Ursache ja schon erklärt, hier ein Vorschlag, wie es funktioniert. Das Beispiel macht so natürlich nicht mehr viel Sinn, angemessener wäre es wohl eine Templatespezialisierung für die Fälle zu schreiben, in denen der zweite Parameter 1 oder 2 ist, aber du solltest erstmal besser noch ein oder zwei Stunden normale Templates lernen, bevor du sowas anfängst.
#include <string> #include <iostream> using namespace std; template<class T> T getValue(string foo, int bar){ switch(bar){ case 1: return (int) 5; case 2: return (string) "lalala"; } } int main(void){ string qry1 = "foobar1"; string qry2 = "foobar2"; int res1 = getValue<int>(qry1, 1); cout << res1 << endl; string res2 = getValue<string>(qry2, 2); cout << res2 << endl; return 0; }
-
naja, dein expliziter aufruf bezieht sich doch auf die argumente! das ist ja nicht sinn der sache...die bleiben ja immer gleich! es soll ja nur der rückgabewert entsprechend geändert werden!

ich such erst mal weiter und guck mir nochmal die template sache an...
-
so wie ich das sehe, geht das nicht mit templates! selbst spezialisierte templates helfen da nicht weiter. es bleibt ja nicht bei den beiden aufrufen (1 und 2), sondern es werden eben noch mehr.
Ich wollte nur die eigentliche Arbeit, die ja immer die gleiche ist, in eine seperate funktion verlegen und dann einen bestimmten wert zurückgeben.
Aber nun bleibt ja nichts anderes übrig, als für jeden fall eine eigene funktion zu schreiben!

vielen dank für eure hilfe
-
sheddy schrieb:
so wie ich das sehe, geht das nicht mit templates! selbst spezialisierte templates helfen da nicht weiter. es bleibt ja nicht bei den beiden aufrufen (1 und 2), sondern es werden eben noch mehr.
Ich wollte nur die eigentliche Arbeit, die ja immer die gleiche ist, in eine seperate funktion verlegen und dann einen bestimmten wert zurückgeben.
Aber nun bleibt ja nichts anderes übrig, als für jeden fall eine eigene funktion zu schreiben!

Wenn du uns erklärst was du wirklich machen möchtest und nicht irgendwelche unklaren Beispiele wie das obige lieferst, kann dir geholfen werden. Wenn nicht, dann musst du selbst weitertüfteln.
-
hmm..dachte das wäre klar gewesen - sorry.
Es soll eine Funktion angeboten werden, die einen Wert zurück gibt. Der Aufrufer der Funktion weiß den Datentypen des Rückgabewerts.
Der Aufrufer möchte zu einer Eigenschaft den Wert haben. Er weiß, dass der Typ der Eigenschaft "int" ist. Also ruft er "int getInt(string)" auf. Möchte er den Wert einer Eigenschaft, die den Typ "float" hat, so ruft er die Funktion "float getFloat(string)" auf.
Mein Versuch war es nun, da vieles in der Funktionen gleich ist und sich nur der Wert, der am Ende zurückgegeben werden soll, sich verändert (float, int, double, etc.) wollte ich alles in EINE Funktion stecken.
Der zweite Parameter meiner template-Funktion sollte den Typen des Datentypen spezifizieren, den ich in der Funktion mit einer Abfrage (if-selse, switch ...) abfragen würde und dementsprechend dann den gewünschten Wert mit dem entsprechenenden Datentypen zurückgebe.
Im Ganzen:
Statt
int getInt(string);
float getFloat(string);soll
*bestimmter Datentyp* getVal(string, int)
ich hoffe, es ist ein wenig klarer geworden.
mfg
-
Sprich, du brauchst so etwas wie den Datentyp Variant? Eine solcher Datentyp Variant kann verschiedene Datentypen aufnehmen. Siehe auch: http://de.wikipedia.org/wiki/Variant und http://www.gamedev.net/reference/articles/article2029.asp .
Gruß Kimmi
-
sheddy schrieb:
hmm..dachte das wäre klar gewesen - sorry.
Es soll eine Funktion angeboten werden, die einen Wert zurück gibt. Der Aufrufer der Funktion weiß den Datentypen des Rückgabewerts.
Der Aufrufer möchte zu einer Eigenschaft den Wert haben. Er weiß, dass der Typ der Eigenschaft "int" ist. Also ruft er "int getInt(string)" auf. Möchte er den Wert einer Eigenschaft, die den Typ "float" hat, so ruft er die Funktion "float getFloat(string)" auf.
Mein Versuch war es nun, da vieles in der Funktionen gleich ist und sich nur der Wert, der am Ende zurückgegeben werden soll, sich verändert (float, int, double, etc.) wollte ich alles in EINE Funktion stecken.
Der zweite Parameter meiner template-Funktion sollte den Typen des Datentypen spezifizieren, den ich in der Funktion mit einer Abfrage (if-selse, switch ...) abfragen würde und dementsprechend dann den gewünschten Wert mit dem entsprechenenden Datentypen zurückgebe.
Im Ganzen:
Statt
int getInt(string);
float getFloat(string);soll
*bestimmter Datentyp* getVal(string, int)
ich hoffe, es ist ein wenig klarer geworden.
mfg
Das geht mit
void *als Rückgabetyp. Allerdings musst du dann jedes mal eine Typ-Umwandlung vornehmen.
-
ich kannte den typen bis eben noch nicht, ABER genau sowas brauche ich

aber anscheinend gibt es sowas nicht in C bzw. C++. Und Zeiger hin- und hercasten wollte ich eigentlich vermeiden.
trotzdem danke für die hilfe....
-
Wo ist in deinen Augen der Unterschied zwischen
int getInt(string); float getFloat(string);und
template <typename T> T get(string);?
Du kannst es dann je nachdem was du brauchst mit get<int>("bla"), get<string>("blubb") usw. aufrufen.
Allerdings ist das alles relativ witzlos wenn du dann eh die ganze Funktion nur als großen switch baust - im Grunde hast du dann nämlich sowas:
template<typename T> T getValue(string foo){ switch(/*type-abhängige konstante*/){ case /*Int-ID*: return getInt(foo); case /*String-ID*/: return getString(foo); } }und landest am Ende doch wieder bei getInt, getString usw.
-
Ein Beispiel:
#include <iostream> #include <string> enum Type { TYPE_INT, TYPE_STRING }; void *myFunction(Type type) { switch (type) { case TYPE_INT: return new int(100); break; case TYPE_STRING: return new std::string("Hey!"); break; } return NULL; } int main() { void *ptr = myFunction(TYPE_INT); if (ptr != NULL) { std::cout << *(int *)ptr << std::endl; } delete ptr; ptr = myFunction(TYPE_STRING); if (ptr != NULL) { std::cout << *(std::string *)ptr << std::endl; } delete ptr; }Wird allerdings sehr spaßig (Casting, Speicherfreigabe).
-
Ich werfe mal noch boost::any in den Raum.
-
Fassen wir das nochmal zusammen:
- Du hast Benutzer, die Werte haben wollen.
- Die Benutzer wissen, was sie haben wollen.
- Es gibt einen Teil, der für jeden Rückgabewert immer gleich ist.
- Es gibt einen Teil, der unterscheidet sich aufgrund des Rückgabetypen.
Hättest Du unterschiedliche Funktionen, würde der Benutzer ja wissen, welche Funktion er aufrufen müsste (siehe Punkt 2).
Wieso dann nicht so?ReturnType somethingCommonForAll(...){...} float getFloat(...) { //... ReturnType var = somethingCommonForAll(...); //... return floatVal; } int getInt(...) { //... ReturnType var = somethingCommonForAll(...); //... return intVal; } //usw.
-
Tachyon hat verstanden, was ich meine! genau so! bei pumuckls lösung ist eben genau dieses "/*type-abhängige konstante*/" das problem! der funktion muss ja schon eine art signal mitgegeben werden, um welchen typ es sich handelt.
und dann funktioniert schon nicht mehr der explizite aufruf der template funktion.und so wie ich das die letzten posts gesagt habe und tachyon vorgeschlagen hat, habe ich es auch jetzt gemacht! im endeffekt auch sinnvoller für den benutzer, der dann die genaue funktion aufruft!
Hättest Du unterschiedliche Funktionen, würde der Benutzer ja wissen, welche Funktion er aufrufen müsste (siehe Punkt 2).
Und da habe ich gedacht, dass EINE funktion reichen würde, die alles bearbeitet. so muss ich jetzt in jeder funktion den "gleichen" quellcode benutzen. im groben und ganzen unterscheiden sich die funktionen kaum - eben bis auf den rückgabewert.
ich arbeite mit den xml-frameworks xerces und xalan und da muss vorher ein wenig mehr vorarbeit geleistet werden, um dann eine gezielte funktion zu nutzen und wollte die arbeit auf eine funktion beschränken!
daher auch mein recht kurzes beispiel am anfang des threads, um den ganzen "rattenschwanz" der xml-frameworks rauszulassen.Im ganzen war es eigentlich eine "optimerung" bzw. faulheit meinerseits

-
sheddy schrieb:
Im ganzen war es eigentlich eine "optimerung" bzw. faulheit meinerseits

Das Vermeiden von doppeltem Code ist allgemein sehr sinnvoll, weil es Änderungen erleichtert und Fehler beim Duplizieren gar nicht erst auftreten können. Das man zusätzlich noch Schreibarbeit spart ist natürlich auch ein willkommener Effekt

-
danke, das wollte ich sagen
