operator [] als Template



  • Hintergrund: Ich habe einen kleinen Parser für Konfigurationsdateien. Der Parser kann gewöhnliche C++-Literale (char const*, int, double, etc) parsen, wobei er intern die Daten auch gleich (mittels Type Erasure) im richtigen Format abspeichert. Ich dachte mir nun, einen operator [] wie folgt zu bauen:

    template <typename T>
    T const& operator [] (std::string const& what);
    

    Aber das geht ja nun wohl nicht. get und at gefällt mir aber irgendwie auch nicht.



  • Wie soll das überhaupt funktionieren, wenn what bestimmt welchen Typ du zurückgibst? Ich kann dir da nicht ganz folgen glaube ich.

    Edit: Ach so, du willst einfach nachgucken ob der Wert nach T konvertierbar ist. Na ja, da würde ich es auch einfach get nennen. foo.get<int>("blubb"); sieht doch nicht so schlimm aus.



  • "what" bestimmt den Typ nicht. Wenn ich schreibe:

    cnf.get<int>("foo");
    

    wird intern ein dynamic_cast ausgeführt, der überprüft, ob "foo" tatsächlich vom Typ int ist. Wenn nicht -> Exception.



  • 314159265358979 schrieb:

    cnf.get<int>("foo");
    

    Gerade editiert. Wie gesagt, ich finde das nicht schlimm so. Der Typ ist anders ja nicht auffindbar und quasi ein zusätzlicher Parameter, insofern erhöht das ja die Redundanz nicht.



  • Wenn die Daten ursprünglich schon als string vorliegen, warum speicherst du sie dann nicht als string ab und konvertierst sie erst beim Aufruf von get<T> nach T?



  • Weil die Daten bereits beim Einlesen validiert werden sollen, da geschieht das Konvertieren in einem Aufwaschen.



  • lazycoder schrieb:

    Wenn die Daten ursprünglich schon als string vorliegen, warum speicherst du sie dann nicht als string ab und konvertierst sie erst beim Aufruf von get<T> nach T?

    Das ist ein andere Art der Datenspeicherung. Wenn man so etwas hat wie xml, ist das natürlich der einzige Weg. Man kann ja beim einlesen auch nicht wissen (sondern nur raten), welchen Typ etwas hat.

    Wenn die Datenstruktur den Typ allerdings speichert, ist das etwas anderes. Dann möchte man vielleicht auch garantiert sofort entdecken ob ein Wert zum Typ passt.
    Wenn das nicht der Fall ist, wie oben gesagt, macht man die Umwandlung natürlich erst bei der Abfrage.

    Edit: Argh, dauernd zu spät in letzter Zeit. -.-



  • Selbst wenn es binär ist, kann man es immer noch im Rohformat speichern und erst beim Auslesen validieren. Noch besser: Wenn nicht alles auf einmal benötigt wird, kann man sequenziell aus der Datei lesen.

    Wenn alles auf einmal passiert hat das nur Nachteile, z.B. muss die ganze Datei zweimal im Speicher behalten werden (Validiert und Nutzung) und es ist langsamer, weil beim langsamen Lesen alles blockiert ist und ein Verwaltungsoverhead (dynamic_cast) da ist.



  • Mit binär/nicht binär hat das weniger zu tun, aber na ja.
    Wie gesagt: Du kannst ja gerne gegen die Validierung argumentieren, aber das ändert nichts daran, dass das die einzige Lösung ist wenn man die Daten prüfen möchte.



  • Habe ich dich richtig verstanden, dass du im Parser die Typen kennst und als Templateparameter setzen könntest?



  • Michael E. schrieb:

    Habe ich dich richtig verstanden, dass du im Parser die Typen kennst

    Ja.

    Michael E. schrieb:

    und als Templateparameter setzen könntest?

    Wie meinst du das?



  • Machs anders rum: gieb einen Proxy zurueck der einen operator T hat.

    Folgendes:

    //dein op[]
    Proxy operator[](string const& what) {
       return Proxy(this, what);
    }
    
    //proxy sieht dann etwa so aus:
    class Proxy {
    private:
      DB* db; // zeiger auf die parser db wo die werte liegen
      string what;
      Proxy(DB* db, string const& what) : db(db), what(what) {}
    public:
       //hier die magie
      template<typename T>
      operator T() {
         return db->get<T>(what);
      }
    };
    

    Man muss natuerlich ueberpruefen was Proxy jetzt alles genau koennen muss - aber prinzipiell ist die Idee die Ausfuehrung des Codes vom op[] in den opT zu verlagern, da wir dort auf den return Typen aufloesen koennen.

    Dann laesst sich ein:

    int i=conf["foo"];
    double f=conf["bar"];
    

    machen.


Anmelden zum Antworten