Wie sollte ein gutes Stringframework aussehen?
-
Am liebsten würde ich wählen können, was die Klasse mir bietet. Wichtig ist, dass ich das gleiche Interface haben will, wenn ich nur einen C-String wrappe oder eine Multibyte unterstützende Stringklasse mit eigener Speicherverwaltung habe. Eigentlich ging Boost.Range ein bisschen in die Richtung, auch wenn die es leider in 1.34 kaputt gemacht haben :(.
string schrieb:
so: http://java.sun.com/javase/6/docs/api/java/lang/String.html
Wenn es um ein Framework für C++ geht, dann sollte es wohl eher heißen "so genau nicht".
-
rüdiger schrieb:
string schrieb:
so: http://java.sun.com/javase/6/docs/api/java/lang/String.html
Wenn es um ein Framework für C++ geht, dann sollte es wohl eher heißen "so genau nicht".
Wieso?
asc schrieb:
1. Die Klasse sollte nicht mit Methoden überladen werden, die keine Stringinterna benötigen (Dafür sind freie Funktionen besser)
Kann man sich jetzt streiten, finde aber die String-Klasse nicht ueberladen.
asc schrieb:
2. Sie sollte vom restlichen Framework nahtlos unterstützt werden (Dies ist ein Faktor der zumindestens für sd::string wohl ab C++09 endlich erfüllt sein wird).
Also das erfuellt die String-Klasse wohl 100%.
asc schrieb:
3. Es sollte eine gute Unicodeunterstützung geben (Auch dies muss nicht zwangsweise in der stringklasse liegen)
Dies ebenfalls.
asc schrieb:
4. Alles weitere wie Konvertierungen etc. lässt sich durch Funktionen oder andere Klassen besser lösen, als durch überfüllung der Klasse.
Die Konvertierungs-Methoden sind Klassenmethoden, sind also ausserhalb des Objektes. In Java geht das halt nicht anders, in C++ waehren das freie Funktionen.
-
DEvent schrieb:
Wieso?
weil das java ist. und in java programmiert man java und in c++ c++.
und das interface von String ist überladen da Java einem technisch kaum eine andere Möglichkeit lässt.
dazu fehlt eben etwas wie char_traits oder vergleichbare funktionalität.
String ist ok für java, aber in c++ würde man da so ziemlich alles anders machen.
-
Shade Of Mine schrieb:
String ist ok für java, aber in c++ würde man da so ziemlich alles anders machen.
Mag das evtl mal jemand konkreter ausführen?
-
Badestrand schrieb:
Shade Of Mine schrieb:
String ist ok für java, aber in c++ würde man da so ziemlich alles anders machen.
Mag das evtl mal jemand konkreter ausführen?
char_traits, die frage ob string wirklich immutable sein sollte im c++ kontext, dazu etwas generative programmierung und ein komplett anderes interface - nämlich keine regex innerhalb der string klasse, und die meisten methoden sind mit stl algos super implementierbar. dazu fehlen dann eben noch iteratoren und die convertTo methoden sind in boost::lexical_cast deutlich besser aufgehoben.
-
DEvent schrieb:
Wieso?
Also mein einziges Argument dafür alles wie in Java in eine Klasse zu stopfen wäre das dann die Objektsyntax möglich ist. Ja, ich mag OOP, aber in C++ als Multiparadigmensprache zieht sind andere Vorgehensweisen optimal.
Leider komme ich erst ab den 18. wieder an meine Bücher, sonst würde ich hierzu mal schauen in welcher Quelle (war entweder Herb Sutter oder Scott Meyer) hierzu einen sehr guten Artikel geschrieben hat (Wann sollte man Funktionen, wann Methoden etc. verwenden).
cu André
-
asc schrieb:
Also mein einziges Argument dafür alles wie in Java in eine Klasse zu stopfen wäre das dann die Objektsyntax möglich ist. Ja, ich mag OOP, aber in C++ als Multiparadigmensprache zieht sind andere Vorgehensweisen optimal.
a.b(c) ist kein bisschen mehr oder weniger oop als b(a,c) oder b.a(c) oder ähnliches.
(Wann sollte man Funktionen, wann Methoden etc. verwenden).
funktion wenn es geht, methoden wenn es sein muss.
-
Badestrand schrieb:
Shade Of Mine schrieb:
String ist ok für java, aber in c++ würde man da so ziemlich alles anders machen.
Mag das evtl mal jemand konkreter ausführen?
Weil in C++ die streams dafür da sind, die ganzen konvertierungen durchzuführen. Die streams verwalten die locales und locales braucht man um anständig Formatierungen durchzuführen. In Java sieht man bereits das Problem, da ist es nämlich nicht wirklich einfach, zahlenformate umzudefinieren. Wenn du einem Stream erlaubst, dass er sich um solche Formatierungen kümmert, musst du auch eine lösung für das Problem finden, dass eine Eingabe im einen Format ankommt und in einem anderen wieder ausgegeben werden soll.
also string1->zahl->string2(anderes zahlenformat). Das geht eigentlich nur, wenn jeder String sein eigenes locale mit sich rumschleppt, und dadurch wird er groß, kompliziert und träge.
In Java ist das nicht so extrem schlimm, weil man sich im Desktopbereich nicht soviel mit locales rumschlagen muss, die meisten Nutzer sind froh, wenn ein und ausgabe dasselbe Format haben. Da dies in C++ allerdings nicht vorausgesetzt werden kann, muss man solche Probleme lösen.
Ähnliches bei den Formatierungen in verschiedene Kodierungen. Das ist eigentlich nicht aufgabe eines streams. Da brauch man sich doch nur mal umschauen wo die Kodierung wichtig wird: bei der ein- und ausgabe. Bei der eingabe wird, soweit erforderlich der String in die programminterne Codierung umgewandelt, und bei der Ausgabe von der Internen Codierung in das Ausgabeformat. Es besteht also keine erforderlichkeit, diese Funktionalität aus den streams auszulagern.
Momentan haben wir in C++ eine schöne einteilung: Streambuffer,stream und String. jeder Teil hat eine eigene, von den anderen Teilen abgegrenzte Aufgabe. Und das ist technisch eine sehr schöne Sache.
-
otze schrieb:
In Java ist das nicht so extrem schlimm, weil man sich im Desktopbereich nicht soviel mit locales rumschlagen muss....
wieso desktop? Java ist im serverbereich auch sehr beliebt.
-
Cool, danke für die guten Erläuterungen!
-
otze schrieb:
Ähnliches bei den Formatierungen in verschiedene Kodierungen. Das ist eigentlich nicht aufgabe eines streams. Da brauch man sich doch nur mal umschauen wo die Kodierung wichtig wird: bei der ein- und ausgabe. Bei der eingabe wird, soweit erforderlich der String in die programminterne Codierung umgewandelt, und bei der Ausgabe von der Internen Codierung in das Ausgabeformat. Es besteht also keine erforderlichkeit, diese Funktionalität aus den streams auszulagern.
Halte ich so pauschal nicht für ganz richtig.
Man muss IMHO unterscheiden zwischen Textstreams und Bytestreams. Ich habe einen Haufen Strings, den stopfe ich in einen Textstream. Der Textstream wird von einem Encoder (z.B. UTF-8) gelesen, der einen Bytestream ausgibt, der dann schließlich in eine Datei geschrieben wird. So hat jede Komponente seine Aufgabe und die Komponenten lassen sich einzeln leicht austauschen.
Ich wüsste jetzt auch nicht, warum das, was du als "Stream" bezeichnest, nämlich der Bytestrom, der in die Datei schreibt, für evtl. Formatierungen von Zahlen zuständig sein sollte. Das klappt nur wenn byte == Zeichen, was nicht gerade eine zukunftssichere Annahme ist. Das bisherige Konzept in der C++ Standardbibliothek sieht nach meinem Verständnis keine Textstreams vor, oder eben nur unter der Annahme, dass byte == Zeichen. Das zeigen auch so Sachen wie eine Datei "als Text" öffnen. Sowas ist IMHO fix und fertig, eine Datei sollte immer als Bytestrom geöffnet werden und was dann reingeschrieben wird, hat so einen Stream nichts anzugehen.
-
c++ hat eben den ansatz dass ein stream formatierungen enthalten kann. wenn ich das nicht will, kann ich in jeden stream immer auch einfach bytefolgen reinwerfen.
die trennung ist bei java imho etwas sauberer gelöst, wenn auch sehr nervig - da ich dauernd adapter erstellen muss. c++ ist da eben pragmatischer was auf dem papier nicht ganz so sauber ist, aber in der verwendung eigentlich ganz praktisch ist.
-
Shade Of Mine schrieb:
c++ hat eben den ansatz dass ein stream formatierungen enthalten kann. wenn ich das nicht will, kann ich in jeden stream immer auch einfach bytefolgen reinwerfen.
die trennung ist bei java imho etwas sauberer gelöst, wenn auch sehr nervig - da ich dauernd adapter erstellen muss. c++ ist da eben pragmatischer was auf dem papier nicht ganz so sauber ist, aber in der verwendung eigentlich ganz praktisch ist.
Ich finde es nicht falsch, wenn ein Stream formattiert - aber das sollte nicht der selbe Stream sein, der eine Bytefolge in eine Datei schreibt. Es sollte ein Textstream sein. Diese Konzepte würde ich auf jeden Fall trennen. Ich denke auch, dass es damals einfach noch kein Thema war, dass byte != Zeichen. Von daher kein Vorwurf, ich würde nur das System heute so nicht als löblich hinstellen.
-
otze schrieb:
In Java ist das nicht so extrem schlimm, weil man sich im Desktopbereich nicht soviel mit locales rumschlagen muss, die meisten Nutzer sind froh, wenn ein und ausgabe dasselbe Format haben. Da dies in C++ allerdings nicht vorausgesetzt werden kann, muss man solche Probleme lösen.
C++ ist doch auf dem Desktopbereich viel mehr vertreten als Java.
Zeigt mal nen C++ Beispielcode mit locales, dass man in Java nicht so einfach hin bekommt.
-
Optimizer schrieb:
Shade Of Mine schrieb:
c++ hat eben den ansatz dass ein stream formatierungen enthalten kann. wenn ich das nicht will, kann ich in jeden stream immer auch einfach bytefolgen reinwerfen.
die trennung ist bei java imho etwas sauberer gelöst, wenn auch sehr nervig - da ich dauernd adapter erstellen muss. c++ ist da eben pragmatischer was auf dem papier nicht ganz so sauber ist, aber in der verwendung eigentlich ganz praktisch ist.
Ich finde es nicht falsch, wenn ein Stream formattiert - aber das sollte nicht der selbe Stream sein, der eine Bytefolge in eine Datei schreibt. Es sollte ein Textstream sein. Diese Konzepte würde ich auf jeden Fall trennen. Ich denke auch, dass es damals einfach noch kein Thema war, dass byte != Zeichen. Von daher kein Vorwurf, ich würde nur das System heute so nicht als löblich hinstellen.
Unicode geht auf 1987 zurueck. 1990 waren bereits Sun, Microsoft, und paar andere dabei, 1991 wurde das erste Buch des Unicode Standards veroeffentlicht, 1992 das zweite.
Im 1987 Original wurde schon an 16bit pro Zeichen gedacht. UTF wurde angefangen 1992 und damals war 32bit fuer ein Zeichen. Die vorletze Spezifikation von C++ war 1998, die letzte 2003. Da war wohl genuegent Zeit...
Ich persoehnlich finde die ganze Sprachunterstuetzung und Formate nur ein Haufen Chaos. Ist alles nur Halbherzig dahingemacht und voller Kompromisse. Das zieht sich durch von normalen Windows-Anwendungen ueber Emails und bis ins Internet.
-
wayne??? schrieb:
Zeigt mal nen C++ Beispielcode mit locales, dass man in Java nicht so einfach hin bekommt.
cin.imbue(locale1); int i; cin>>i; cout.imbue(locale2); cout<<i;
@optimizer
Ich finde es nicht falsch, wenn ein Stream formattiert - aber das sollte nicht der selbe Stream sein, der eine Bytefolge in eine Datei schreibt. Es sollte ein Textstream sein. Diese Konzepte würde ich auf jeden Fall trennen.
Vielleicht reden wir aneinander vorbei. aber das ist doch in C++ getrennt. Der stream formatiert, der buffer schreibt. Es ist also nicht dasselbe Objekt.
-
otze schrieb:
@optimizer
Ich finde es nicht falsch, wenn ein Stream formattiert - aber das sollte nicht der selbe Stream sein, der eine Bytefolge in eine Datei schreibt. Es sollte ein Textstream sein. Diese Konzepte würde ich auf jeden Fall trennen.
Vielleicht reden wir aneinander vorbei. aber das ist doch in C++ getrennt. Der stream formatiert, der buffer schreibt. Es ist also nicht dasselbe Objekt.
Wo genau käme dann eine bestimmte Kodierung ins Spiel? Also ich habe jetzt folgendes:
#include <fstream> using namespace std; int main() { string s("geiler string"); wofstream file("test.txt"); file << s.c_str() << endl; }
Das Programm schreibt 15 Bytes, normalen ANSI plain text. Also so einen basic_ofstream<wchar_t> zu verwenden bewirkt nicht, dass irgendwie in der Kodierung von wchar_t geschrieben wird (wäre bei mir UTF-16), sondern es schreibt offensichtlich was im String, im Arbeitsspeicher steht, 1:1 ab in die Datei. Jetzt ist bekannt, dass C++ nicht fertige Lösungen zum Beispiel für die Formate UTF-8, UTF-16 usw. anbietet.
Aber gibt es irgendwie ein generisches Framework, so dass ich etwas einklinken kann, was die Kodierung von Zeichen nach Bytes steuert? Ich sehe es nicht. Ich sehe nicht, wie die buffer das machen können sollen. Nochmal, IMHO wäre ein sauberes Konzept:
(jede Menge Strings, es sollte egal sein, welcher Zeichentyp)
Textstream
Encoder
Bytestream
Datei
Sodass man sich eine Pipeline nach seinem Geschmack zusammenstecken kann, zum Beispiel Textstream<char>, Encoder(UTF-8), Bytestream("test.txt"). Ich sehe sowas in der Art nicht verwirklicht. Ich habe das Standard C++-I/O allerdings auch immer gemieden und die OS-Funktionen dafür benutzt. Vielleicht übersehe ich was.
-
otze schrieb:
cin.imbue(locale1); int i; cin>>i; cout.imbue(locale2); cout<<i;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); Number n = NumberFormat.getInstance(Locale.ENGLISH).parse(in.readLine()); System.out.println(NumberFormat.getInstance(Locale.GERMAN).format(n));
Gut, das einlesen von der Konsole ist umständlicher, aber welches Programm bei dem Internationalisierung wichtig ist liest schon von Konsole.
Habs noch nie probiert, aber geht sowas in C++ auch so einfach?
System.out.println(DateFormat.getDateInstance(DateFormat.LONG, Locale.GERMAN).format(Calendar.getInstance().getTime()));
-
Optimizer schrieb:
Das Programm schreibt 15 Bytes, normalen ANSI plain text. Also so einen basic_ofstream<wchar_t> zu verwenden bewirkt nicht, dass irgendwie in der Kodierung von wchar_t geschrieben wird (wäre bei mir UTF-16), sondern es schreibt offensichtlich was im String, im Arbeitsspeicher steht, 1:1 ab in die Datei. Jetzt ist bekannt, dass C++ nicht fertige Lösungen zum Beispiel für die Formate UTF-8, UTF-16 usw. anbietet.
Ein wunder ist, dass es überhaupt bei dir funktioniert. laut standard gibt es nämlich nur einen gültigen stream ausgabeoperator:
template<class charT,class traits, class Allocator> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,basic_string<charT,traits,Allocator);
du müsstest also einen compile fehler kriegen, weil dein string auf char und dein stream auf wchar_t läuft. Aber du hast recht, egal wie mans dreht und wendet, C++ unterstützt standarmäßig nicht, dass beliebige stringtypen ausgegeben werden können.
Das ist aber so direkt kein Problem, es gibt ja den streambuffer. Wenn man Intern nur mit einem zeichentyp arbeitet, zum Beispiel char, dann kann der streambuffer das Erledigen. Er hat zugriff auf die locales(genauer er speichert sie) und damit auf die facets ctype und codecvt. Ob die Buffer diese funktionalität standardmäßig nutzen ist wohl implementationsabhängig. Wenn die Console nur Unicode versteht, wird die Ausgabe wohl nach unicode umgewandelt.Wichtig ist in diesem Zusammenhang nur, dass die Buffer die Möglichkeiten dazu besitzen, dass es umgewandelt werden kann.
Zusammengefasst: die konvertierung stringtyp<->streamtyp ist nicht automatisch möglich aber streamtyp<->ausgabetyp sehr wohl. Und das ist ja das wichtige. Solange die Streams die konvertierung "interner typ"->"externer typ" erbringen können ist alles in butter. Man muss nur damit rechnen, dass man im ernstfall nen eigenen bufferwrapper schreiben muss, aber soweit ich weis, gibts da was in boost.
wayne??? schrieb:
Habs noch nie probiert, aber geht sowas in C++ auch so einfach?
System.out.println(DateFormat.getDateInstance(DateFormat.LONG, Locale.GERMAN).format(Calendar.getInstance().getTime()));
ein einzeiler ist es leider nicht
ist ungetestet, aber so müsste das aussehen(direkt mit locales arbeiten ist ein gräuel
)
//locale holen locale loc=cout.getloc(); //facet holen time_put<char>& tfac = use_facet<time_put<char> >(loc); //ausgabe tm time=localtime(time(0)); tfac.put(cout,cout,' ',&tm,'c',' ');
das ganze dann als einzeiler:
use_facet<time_put<char> >(cout.getloc()).put(cout,cout,' ',&localtime(time(0)),'c',' ');
-
Gibts außer C++ noch eine Sprache die Streams als Standardmittel zur Konvertierung zwischen Strings und zahlen hat?