Template Funktionen - Korrektur?
-
Ersteinmal Hallo an alle, hab mich so eben frisch registriert

Ich höre zur Zeit C++ für Fortgeschrittene an meiner Uni. Heute am ersten Tag ging es außschließlich um Templates. Wir bekamen die Aufgabe:
a) Schreiben Sie Funktionen length(str) und charAt(str, i), mit denen man die
Länge bzw. das i-te Zeichen eines Strings str ermitteln kann, und zwar sowohl
für Strings der Standard-Bibliothek (basic_string) als auch für 0-terminierte char
arrays ("c-style Strings").b) Schreiben Sie ein einzelnes Funktions-Template printRev(str), das unter
Verwendung von length(str) und charAt(str, i) einen String str rückwärts
ausgibt.An sich hätte ich Überladen verwendet, da es aber nur um Templates ging, hab ich es also mit desgleichen gelöst:
Es funktioniert zwar soweit alles - aber ich hab heute zum ersten Mal mich mit Templates beschäftigt, kenne nur Generics aus Java.
Könnte jemand mal rübergucken, ob das vernünftig realisiert ist?
Würde mich sehr freuen,
BrokenClockwork

-
Ja finde ich persönlich gut gelöst, hätte daran eigentlich nichts auszusetzen.
-
Ich verstehe nicht ganz, weshalb du so einen komplizierten Umweg über die
Value-Struktur gehst und dann trotzdem wieder Überladung verwendest. Templates sind ein anderes Konzept. FürcharAt()kannst du noch generisch arbeiten, beilength()musst du hingegen Fälle unterscheiden. Da wäre Überladung um Längen sinnvoller gewesen, aber mit Template-Spezialisierung kann man das auch hinbiegen. Nur muss man die willkürliche Entscheidung treffen, welches der allgemeine und welches der spezielle Fall ist.Das Funktionstemplate
charAt()hätte ich so implementiert:template <typename StringType> char charAt(const StringType& str, unsigned int i) { return str[i]; }Wichtig ist auch, dass du beim Aufruf die Typen nicht explizit angibst, denn dann gewinnst du eigentlich nichts gegenüber zwei benannten Funktionen. Der Compiler kann den Typ des Arguments herleiten. Also
charAt(a,0)statt
charAt<string>(a,0)Und füge doch nächstes Mal Code direkt hier ins Forum ein. Dazu gibts die [cpp]-Tags (erste weisse Schaltfläche mit Aufschrift "C/C++").
-
Geht es nicht um Spezialisierung von Funktionstemplates?
-
Gut, kann man so oder so sehen
Aber jetzt wo ein bisschen Kritik kommt, hab ich den Code auch mal in meine IDE reingeworfen und mein Compiler meckert sogar beichar charAt(typename Value<TString>::CString s, int i) // int length(typename Value<TString>::CString s)Das typename und ::CString gefällt ihm nicht. Was benutzt du denn für eine Entwicklungsumgebung?
-
Zeus schrieb:
Geht es nicht um Spezialisierung von Funktionstemplates?
Scheint so, aber dafür ist die Aufgabenstellung ziemlich schlecht. Abgesehen davon ist Spezialisierung bei Funktionstemplates ohnehin eine fragwürdige Angelegenheit. In vielen Fällen ist Überladung besser geeignet (weil flexibler) und erspart Überraschungen, was das Auswahlverfahren der richtigen Funktion betrifft.
FreakY<3Cpp schrieb:
Aber jetzt wo ein bisschen Kritik kommt, hab ich den Code auch mal in meine IDE reingeworfen und mein Compiler meckert sogar bei [...]
Darum geht es doch nicht. Das Problem ist, dass Templates falsch verstanden und eingesetzt werden. Oder kannst du mir verraten, welchen Sinn das
TbeiValuehat? Hier liegt eine völlig falsche Herangehensweise vor. Als Lektüre sei mal dieser Artikel erwähnt.Hier ist übrigens der Originalcode kopiert, um ihn länger zu erhalten und den Helfern das Link-Anklicken zu ersparen.

#include <iostream> #include <string> #include <cstring> using std::string; /* Exercise 1.a */ template <typename T> struct Value { typedef char CString[]; typedef string CppString; }; template <typename TString> int length(typename Value<TString>::CppString s) { return s.length(); } template <typename TString> char charAt(typename Value<TString>::CppString s, int i) { return s[i]; } template <typename TString> int length(typename Value<TString>::CString s) { return strlen(s); } template <typename TString> char charAt(typename Value<TString>::CString s, int i) { return s[i]; } /* Exercise 1.b */ template <typename TString> TString printRev(string s) { string result(s.begin(), s.end()); reverse(result.begin(), result.end()); return result; } /* main() for test purposes */ int main() { string a = "Hello Berlin"; char b[] = "Hello Berlin again"; std::cout << length<string>(a) << std::endl; std::cout << length<char[]>(b) << std::endl; std::cout << charAt<string>(a,0) << std::endl; std::cout << charAt<char[]>(b,1) << std::endl; std::cout << printRev<string>(a) << std::endl; std::cout << printRev<string>(b) << std::endl; }
-
Ich hätte irgendwie an sowas gedacht:
(const und Refrenzen soweit möglich absichtlich weggelassen)#include <string> #include <iostream> #include <cstring> using namespace std; //Anmelden, daß es length gibt template <typename STRING> int length(STRING str); //Geht für s1 und s2 template<> int length(char* str){ return strlen(str); } //Spaßige Optimierung für s1, brauchen wir gar nicht template<int SIZE> int length(char (&str)[SIZE]){ return SIZE-1; } //geht für s3 template<> int length(string str){ return str.length(); } int main() { char s1[]="hallo"; char* s2=&s1[1]; string s3="c++"; cout<<length(s1)<<'\n'; cout<<length(s2)<<'\n'; cout<<length(s3)<<'\n'; }
-
Danke ersteinmal für die vielen Antworten. Ja Nexux, ich finde Überladen auch besser und ich denke auch das die Aufgabenstellung schlecht formuliert ist.
Ich habe mal meine neue Version angefügt.
#include <iostream> #include <string> #include <cstring> using std::string; /* Exercise 1.a */ template <typename T> struct Value { typedef char CString[]; typedef string CppString; }; template <typename TString> int length(typename Value<TString>::CppString s) { return s.length(); } template <typename TString> int length(typename Value<TString>::CString s) { return strlen(s); } template <typename TString> char charAt(const TString &s, unsigned int i) { return s[i]; } /* Exercise 1.b */ template <typename TString> string printRev(const TString &s) { string result(length<TString>(s), ' '); int l = length<TString>(s); for (int i = 0; i != l; ++i) { result[i] = charAt(s,l-i-1); } return result; } /* main() for test purposes */ int main() { string a = "Hello Berlin"; char b[] = "Hello Berlin again"; std::cout << length<string>(a) << std::endl; std::cout << length<char[]>(b) << std::endl; std::cout << charAt(a,0) << std::endl; std::cout << charAt(b,1) << std::endl; std::cout << printRev(a) << std::endl; std::cout << printRev(b) << std::endl; }
-
Nexus schrieb:
Das Problem ist, dass Templates falsch verstanden und eingesetzt werden. Oder kannst du mir verraten, welchen Sinn das
TbeiValuehat?
... Du hast natürlich Recht, das hab ich völlig übersehen.BrokenClockwork schrieb:
Ich habe mal meine neue Version angefügt.
Der Fehler ist immer noch da. Du benutzt ein Template bei deiner Struktur, obwohl dies überhaupt kein Sinn macht, denn du nutzt es garnicht.
-
Ach jetzt seh ich erst was gemeint ist, das ist wirklich grässlich... keine Ahnung wie man das mit Templates und eben nicht Überladen realisiert

Edit: Naja schlussendlich ähnlich wie Volkard, danke
