Unterschiedliche Returntypen (.ini parser)?
-
Noobey schrieb:
Boost ist mir noch zu viel.
Kann jemand vielleicht ein Minimalbeispiel erstellen?Die Idee ist eigentlich ,dass du dadurch nicht mehr, sondern weniger Arbeit hast.
-
Meine Implementation eines .ini-Readers:
http://code.google.com/p/nightlighttv/source/browse/NightLight/trunk/NightLightDLL/NLConfigManager.cpp
http://code.google.com/p/nightlighttv/source/browse/NightLight/trunk/NightLightDLL/NLConfigManager.hppVllt hilfts Dir was.. Lizenz aber beachten wenn Du es klaust ;).
Danke.
rya.
-
Scorcher24 schrieb:
Meine Implementation eines .ini-Readers:
http://code.google.com/p/nightlighttv/source/browse/NightLight/trunk/NightLightDLL/NLConfigManager.cpp
http://code.google.com/p/nightlighttv/source/browse/NightLight/trunk/NightLightDLL/NLConfigManager.hppVllt hilfts Dir was.. Lizenz aber beachten wenn Du es klaust ;).
Danke.
rya.Ist sehr viel (überflüssiger) redundanter Code drinne.
-
TyRoXx schrieb:
So ungefähr könnte man es machen.
...hmmm ... muss aber der (auslesende) Aufrufer nicht trotzdem explizit angeben, welchen Typ er erwartet?
Auch sollte get() noch einen Mechanismus vorsehen, falls der Typ nicht konvertierbar ist (op>> fehlschlägt) ...
... und für "nicht-default-konstruierbare" Typen müsste man auch einiges frickeln (bzw. geeignet spezialisieren).
Aber die Verwendung des op>> finde ich prinzipell gut.
Vielleicht besser mit output-Parameter - dann kann man die automatische Typdeduktion nutzen und hat nicht unbedingt das Problem der def-Konstruktion (es muss nur bereits überhaupt konstruiert sein):template <class T> bool get(const std::string &cat, const std::string &ent, T& erg) { std::stringstream ss; ss.str(categories[cat][ent]); return(ss >> erg); }Gruß,
Simon2.
-
Kann man meiner Meinung nach noch weiter verbessern:
1. Ich würde beide Methoden anbieten (Simon2 und TyRoXx).
2. Exceptions wären hier für den Fehlschlag besser geeignet. Sowas sollte ja wirklich eine Ausnahme darstellen.class ini_bad_type : public std::exception { private: std::string m_category; std::string m_entity; std::string m_value; public: ini_bad_type(std::string const& cat, std::string const& ent, std::string const& val) : m_category(cat) , m_entity(ent) , m_value(val) { } public: virtual char const* what() const throw() { return "ini_bad_type"; } std::string const& get_category() const { return m_category; } std::string const& get_entity() const { return m_entity; } std::string const& get_value() const { return m_value; } }; // irgendwo in einer Klasse dann... template<typename T> T& get(std::string const& cat, std::string const& ent, T& result) const { std::string const& value = categories[cat][ent]; std::istringstream iss(value); // Hat jemand einen besseren Vorschlag dafür, wie man prüfen kann, // ob alles eingelesen wurde? if(iss >> result && iss.gcount() == value.length()) { return result; } throw ini_bad_type(cat, ent, value); } template<typename T> T get(std::string const& cat, std::string const& ent) const { T result; return get(cat, ent, result); }Grüssli
-


Gruß,
Simon2.
-
// Hat jemand einen besseren Vorschlag dafür, wie man prüfen kann, // ob alles eingelesen wurde?Guck dir mal
boost::lexical_castan.
http://www.boost.org/doc/libs/1_43_0/libs/conversion/lexical_cast.htm->
template<typename T> T get(std::string const& cat, std::string const& ent) const { return boost::lexical_cast<T>(categories[cat][ent]); // throws boost::bad_lexical_cast }Die Optimierung über
T&ist zwar grundsätzlich nett, in diesem Fall aber IMO etwas deplaziert.
-
hustbaer schrieb:
Guck dir mal
boost::lexical_castan.
http://www.boost.org/doc/libs/1_43_0/libs/conversion/lexical_cast.htmIch kenne
boost::lexical_castschon, verwende es ja auch regelmässig. Wollte aber nicht gleich wieder Boost einsetzen. Und ich kann es aktuell auch nicht nachschauen, wie esboost::lexical_castmacht, da ich hier grad kein Boost habe und nicht das ganze Paket runterladen wollte, nur um das nachzuschauen
Übrigens, in meiner Überprüfung, ob alles gelesen wurde, hat sich ein Fehler eingeschlichen, findet ihn jemand?

hustbaer schrieb:
Die Optimierung über
T&ist zwar grundsätzlich nett, in diesem Fall aber IMO etwas deplaziert.Was genau meinst du damit?

Grüssli
-
Dravere schrieb:
Übrigens, in meiner Überprüfung, ob alles gelesen wurde, hat sich ein Fehler eingeschlichen, findet ihn jemand?

Hier:
public: virtual ...Sowas geht gar nicht!

(Sorry, aber im Hinblick auf die andere Diskussion war die Frage zu einladend. Nur nicht ernst nehmen ;))
-
Nexus schrieb:
Dravere schrieb:
Übrigens, in meiner Überprüfung, ob alles gelesen wurde, hat sich ein Fehler eingeschlichen, findet ihn jemand?

Hier:
public: virtual ...Sowas geht gar nicht!

(Sorry, aber im Hinblick auf die andere Diskussion war die Frage zu einladend. Nur nicht ernst nehmen ;))
Das nennt man self-owned. xD
-
Dravere schrieb:
hustbaer schrieb:
Die Optimierung über
T&ist zwar grundsätzlich nett, in diesem Fall aber IMO etwas deplaziert.Was genau meinst du damit?

* IMO müsste hier die NRVO greifen.
* Wenn's die nicht packt, dann Move-Semantik (aktuellen Compiler + Std. Library vorausgesetzt).
* Was liest man aus .ini Files, was mit einem stringstream/lexical_cast konvertiert werden müsste? Fallen mir jetzt nur Typen ein die wahnsinnig billig zu kopieren sind (Integers & Floats). Bleiben noch Strings, aber die müsste man nicht konvertieren. Eine Spezialisierung für std::(w)string würde hier wesentlich mehr bringen als eine Variante mit Output-Parameter.
* Ich würde eine Funktion zum Lesen von Konfigurationsdaten nicht besonders optimieren. Zumindest nicht bevor mir mein Profiler sagt dass ich es tun sollte.
* Wenn man die Funktion wirklich unbedingt optimieren will, dann sollte man IMO den stringstream eliminieren. Was zugegebenermassen viel Arbeit ist. Die ich mir wie schon gesagt nicht antun würde, weil ich so eine Funktion gar nicht optimieren würde
-
Dravere schrieb:
Und ich kann es aktuell auch nicht nachschauen, wie es
boost::lexical_castmacht, da ich hier grad kein Boost habe und nicht das ganze Paket runterladen wollte, nur um das nachzuschauen
google "boost lexical_cast" -> Zweiter link:
http://www.boost.org/doc/libs/1_43_0/boost/lexical_cast.hppdie haben die meisten (oder alle) header lesbar im Netz

-
pumuckl schrieb:
Das ist ein Witz, oder?
-
> Das ist ein Witz, oder?
1213 Zeilen Code für lexikalische Konvertierung? Das kann ich auch nicht nachvollziehen. Mit std::stringstream ist das ein 3-Zeiler?!

-
hustbaer schrieb:
Dravere schrieb:
hustbaer schrieb:
Die Optimierung über
T&ist zwar grundsätzlich nett, in diesem Fall aber IMO etwas deplaziert.Was genau meinst du damit?

* IMO müsste hier die NRVO greifen.
* Wenn's die nicht packt, dann Move-Semantik (aktuellen Compiler + Std. Library vorausgesetzt).
* Was liest man aus .ini Files, was mit einem stringstream/lexical_cast konvertiert werden müsste? Fallen mir jetzt nur Typen ein die wahnsinnig billig zu kopieren sind (Integers & Floats). Bleiben noch Strings, aber die müsste man nicht konvertieren. Eine Spezialisierung für std::(w)string würde hier wesentlich mehr bringen als eine Variante mit Output-Parameter.
* Ich würde eine Funktion zum Lesen von Konfigurationsdaten nicht besonders optimieren. Zumindest nicht bevor mir mein Profiler sagt dass ich es tun sollte.
* Wenn man die Funktion wirklich unbedingt optimieren will, dann sollte man IMO den stringstream eliminieren. Was zugegebenermassen viel Arbeit ist. Die ich mir wie schon gesagt nicht antun würde, weil ich so eine Funktion gar nicht optimieren würde
Verstehe ich dich richtig, dass du damit meinst, dass man die ganze Funktion weglassen soll, welche einen dritten Parameter
T&hat? Das war mir nämlich noch nicht so ganz klar, ob du meinst, ob man die Funktion weglassen soll oder nur die Referenz entfernen sollte.
Ich habe jedenfalls diese Funktion nicht hingeschrieben, weil ich an irgendeine Optimierung dachte, sondern an nicht triviale Konstruktoren. Ich muss dir aber zustimmen, dass die Chance für solche Typen eher sehr gering ist
pumuckl schrieb:
die haben die meisten (oder alle) header lesbar im Netz

Ok, ok, ich gebe ja zu, ich war nur zu faul

Sie machen es übrigens einfach mit einem zusätzlichen
getdanach und Überprüfung aufEOF.typedef std::istringstream input_stream; typedef input_stream::traits_type input_traits; std::istringstream iss; if(iss >> result && iss.get() == input_traits.eof()) { // Erfolg! }Der Fehler oben war übrigens, dass ich
gcountverwendet habe, zum Überprüfen einer formatierten Eingabe.gcountliefert aber nur die Menge der gelesenen Zeichen der letzten unformatierten Eingabe.otze schrieb:
pumuckl schrieb:
Das ist ein Witz, oder?
Ad aCTa schrieb:
1213 Zeilen Code für lexikalische Konvertierung? Das kann ich auch nicht nachvollziehen. Mit std::stringstream ist das ein 3-Zeiler?!

Schaut euch mal den Code genauer an, statt nur die Anzahl Zeilen zu zählen. Ihr könnt auch gerne mal mit einem Profiler die Geschwindigkeit des 3-Zeilers in einer Funktion mit dem
boost::lexical_castvergleichen. Ich würde mal behaupten aus längst vergangenen Messungen, dassboost::lexical_castca. 4 mal schneller ist. Die haben zahlreiche Optimierungen vorgenommen. Wenn man sogar genau hinschaut, so wird bei Standardtypen (double, float, int, usw.) keinstd::stringstreamverwendet. Nicht mal irgendein IOStream aus der Standardbibliothek, sondern es werden eigene "Streams" verwendet. Der Trick ist, dass für diese Typen die maximale Grösse als Strings ausgerechnet wird und zwar zur Kompilezeit. Danach wird Speicher dafür auf dem Stack geholt und in diesen Speicher dann geschrieben. Somit musste auch eigener Code her, welcher mit dem aktuellenstd::localdie Zahlen formatiert oder entsprechend einliest
Und beim Cast in einenstd::string, da wird dann zum Beispiel gleich der Puffer desstd::stringgenommen, statt noch über einen anderen Puffer zu gehen. usw. usf. Lest euch selber in den Code ein
Grüssli
PS: @Nexus, kann doch nix dafür, wenn der Standard mir das vorschreibt
... 