std::string nach Typ casten



  • Ich habe eine Template-Klasse, die hat einen generischen Typen als Attribut. Z.B.

    T m_value;
    

    Jetzt kann dieser Wert von außen gesetzt werden, allerdings kommt der neue Wert stets als std::string
    (da die Daten über das Netzwerk verschickt werden).
    Jetzt möchte ich im Prinzip die Schönheit der Templates erhalten und daher z.B. NICHT noch mitschicken
    wie der std::string denn zu interpretieren ist oder dass die Klasse sich zusätzlich merkt, von
    welchem Typ denn jetzt T ist (dann ist das Template ja fast wieder überflüssig).

    Vielmehr suche ich einen Ansatz ähnlich wie das hier:

    m_value = type_cast< typeid(m_value) > (valAsString);
    

    Jetzt nur als grobe Idee! Mir ist klar, dass man einen string so nicht casten kann und syntaktisch
    geht das mit typeid auch nicht. Aber es hilft aufzuzeigen, wie ich mir das elegant vorstelle.
    Hat wer von euch eine Idee?

    Viele Grüße, schönen Dienstag 🙂



  • z.B. mittels lexical_cast oder einfach per (i)stringstream:

    istringstream istr(str);
    T t = T();
    istr >> t;
    


  • Schablone123 schrieb:

    Ich habe eine Template-Klasse, (...)

    Nein, hast du nicht. Du hast eine Klassen-Template bzw. Klassenvorlage. Und da liegt auch das Verständnisproblem.

    Eine Template existiert nur für den Compiler, um daraus nach Bedarf Klassen respektive Funktionen zu stanzen. Zur Laufzeit ist die Template nicht mehr vorhanden, und es ist der Laufzeitumgebung daher auch nicht möglich, zur Laufzeit zu entscheiden, mit welchen Parametern eine Template konkretisiert werden soll. Zumal sich auch die Frage stellt, wie der Compiler mit etwas arbeiten soll, dessen Typen er nicht kennt.

    Wenn du zur Compilezeit weißt, welchen Typ du zur Laufzeit geschickt bekommen wirst, ist die Sache aber simpel:

    m_value.parse(val_as_string);
    


  • Mach's doch über boost::lexical_cast. Für eigene Typen muss du dann nur entsprechende Stream-Operatoren überladen, also operator>>(std::istream&,meinTyp&). lexical_cast verwendet auch nur die Streamoperatoren. Die sind ja für viele built-in-Typen schon definiert.

    m_value = boost::lexical_cast<T>(valAsString);
    

    Achte darauf, dass du die Operatoren für eine Klasse X in demselben Namensraum deklarierst, wo auch X deklariert wird. Dann ist er für lexical_cast wegen ADL (argument dependent lookup) aufrufbar.



  • seldon schrieb:

    Wenn du zur Compilezeit weißt, welchen Typ du zur Laufzeit geschickt bekommen wirst, ist die Sache aber simpel:

    m_value.parse(val_as_string);
    

    oder auch

    namespace myio {
      void parse(string const& x, int&);
      void parse(string const& x, double&);
      :::
    }
    
      :::
      using myio::parse; // Fallback für int, double, etc
      parse(val_as_string,m_value); // ADL anwendbar
      :::
    

    Aber das mit den Streamoperatoren und boost::lexical_cast liegt irgendwie näher, finde ich.



  • Lexical_cast kann man machen. Wenn man es hinkriegt, sind freie Funktionen natürlich besser, aber ich vermute, dass die betreffende Routine nachher Zugriff auf die Klasseninterna braucht.

    Stream-Operatoren sind natürlich schick, aber wie viel Sinn das macht, hängt vom Drumherum ab. Wenn aus dem Netzwerksocket ein Zeichenstrom kommt, aus dem eine Objektbeschreibung nach der anderen kommt - klar, Stream-Interface drum, istream_iterator drauf, std::copy. Wenn es mehr so ist, dass die Daten paketweise kommen und der Inhalt eines Paketes für ein Objekt steht, lässt sich das u.U. nicht so einfach auf einen std::istream mappen, und dann stünde man mit einer parse-Methode besser da.



  • Erstmal danke euch.

    krümelkacker schrieb:

    Mach's doch über boost::lexical_cast. Für eigene Typen muss du dann nur entsprechende Stream-Operatoren überladen, also operator>>(std::istream&,meinTyp&). lexical_cast verwendet auch nur die Streamoperatoren. Die sind ja für viele built-in-Typen schon definiert.

    m_value = boost::lexical_cast<T>(valAsString);
    

    Achte darauf, dass du die Operatoren für eine Klasse X in demselben Namensraum deklarierst, wo auch X deklariert wird. Dann ist er für lexical_cast wegen ADL (argument dependent lookup) aufrufbar.

    Hm ja, dass es in der Tat so einfach ist, hatte ich ja nicht gedacht. Das Template wird ja entsprechend zur Compilezeit ausgeprägt, also kann man den cast schon zur Compilezeit festlegen. Da ich quasi nur built-in-Datentypen verwende, sollte das so ausreichend sein



  • Ich war aber erster 😃


Log in to reply