Template Vector/List, aus Datei einlesen



  • Leider komme ich bei folgendem Problem nicht weiter.

    Zunächst habe ich eine Template-Methode write, die den Inhalt eines STL-Containers (vector oder list) in eine Datei schreibt.

    template<class T> void write(T t, std::string filename){
    
        std::offstream myfile(filename.c_str());
        int size = t.size();
        std::reverse(t.begin(), t.end());
        for(int i=0; i< size; i++){
            myfile << t.back() << '\n';
            t.pop_back();
        }
        myfile.close();
    }
    

    Aus dieser Datei möchte ich die Daten nun wieder in einem STL-Container speichern.

    Zunächst der Code, den ich mir bisher überlegt habe:

    template<class T> void read (T& tm std::string filename){
    
        std::ifstream myfile(filename.c_str());
        std::string line;
    
        if(myfile.is_open(){
            whilte(myfile.good()){
                getline(myfile, line);
                t.push_back(line);
            }
        myfile.close();
        }
    }
    

    Das funktioniert für einen Vector mit Strings auch gut. Das ist aber nur ein Spezialfall. Sobald wir Vectoren von Floats oder so haben, geht alles über die Wupper. Ich habe mich schon verzweifelt am Casten versucht, aber auch ohne Erfolg.

    Wir kann ich aus dem übergebenen Parameter T herauslesen, welchen Typ er hat (float, String, double ,...) und wie caste ich anschließend den String in die verschiedenen Typen?

    Im Voraus vielen Dank für eure Hilfe.



  • Du gehst alles falsch an.

    Strings sind auch nur Arrays. Das heißt, du musst, wenn du alles selbst serialisieren willst, auch die Strings erstmal irgendwie serialisieren.

    Kleiner Tipp: Um Arrays zu serialisieren musst du vorher die Größe angeben, sonst funktioniert gar nichts.

    Bspw um Strings einzulesen und schreiben:

    template<typename IterT>
    std::ostream& write(std::ostream& is, IterT first, IterT last)
    {
        is << std::distance(first, last);
        std::copy(first, last, std::ostream_iterator<std::iterator_traits<IterT>::value_type>(is));
        return is;
    }
    
    template<typename IterT>
    std::istream& read(std::istream& is, IterT outputIter)
    {
        std::size_t t = *istream_iterator<std::size_t>(is);
        std::copy_n(std::istream_iterator<std::iterator_traits<IterT>::value_type>(is), t, outputIter);
        return is;
    }
    

    (Ungetestet!)

    Wieso nimmst du nicht einfach Boost.Serialization? Da wird alles schon gemacht...



  • Im Thread deins Kollegen steht das schon: http://www.c-plusplus.net/forum/311037

    typename T::value_type value;
    


  • Sone schrieb:

    Du gehst alles falsch an.

    Strings sind auch nur Arrays. Das heißt, du musst, wenn du alles selbst serialisieren willst, auch die Strings erstmal irgendwie serialisieren.

    Kleiner Tipp: Um Arrays zu serialisieren musst du vorher die Größe angeben, sonst funktioniert gar nichts.

    Bspw um Strings einzulesen und schreiben:

    template<typename IterT>
    std::ostream& write(std::ostream& is, IterT first, IterT last)
    {
        is << std::distance(first, last);
        std::copy(first, last, std::ostream_iterator<std::iterator_traits<IterT>::value_type>(is));
        return is;
    }
    
    template<typename IterT>
    std::istream& read(std::istream& is, IterT outputIter)
    {
        std::size_t t = *istream_iterator<std::size_t>(is);
        std::copy_n(std::istream_iterator<std::iterator_traits<IterT>::value_type>(is), t, outputIter);
        return is;
    }
    

    (Ungetestet!)

    Wieso nimmst du nicht einfach Boost.Serialization? Da wird alles schon gemacht...

    Ich muss ehrlich sagen, ich komme da grad nicht mit.

    Der Aufruf erfolgt durch (das kann ich nicht ändern):

    write(string_vec, "example.dat");
    

    mit

    string_vec = std::vector<std::string> strings;
    

    (Inhalt dann noch dazu).

    Das passt doch dann bei deinem Aufruf garnicht mehr, oder irre ich mich?



  • keinkollege schrieb:

    Im Thread deins Kollegen steht das schon: http://www.c-plusplus.net/forum/311037

    typename T::value_type value;
    

    Wie kann ich mit diesem value, nun einen Cast durchführen:

    Sinngemäß:

    t.push_back((value) line);
    

    wäre mein Ziel



  • Lies halt mit operator>> anstatt mit getline ein.



  • keinkollege schrieb:

    Lies halt mit operator>> anstatt mit getline ein.

    Kannst du vllt kurz einen Beispielcode dazu zeigen? Was ist denn hier operator? Mit den Begriffen komme ich bezüglich c++ noch garnicht klar 😞

    cin >> variable;
    

    kenne ich zum Einlesen aus der Eingabve



  • template<class T>
    std::istream& operator>>(std::istream &is, T & vec)
    {
    	is >> vec.back();
    
    	return is;
    }
    

    sowas in der art meint er. aber ich kann da grad kein gutes beispiel für geben, hab den thread nicht aufmerksam mitverfolgt und auch nicht wirklich zeit dafür 😉

    du müsstest halt hier reinschreiben, wie dein vector gelesen wird (egal ob aus datei oder standardeingabe oder oder oder)

    und benutzt wird das dann so

    std::vector<std::string> vec;
    
    cin >> vec;
    
    //oder
    std::ifstream file("lol.txt");
    file >> vec;
    


  • Mit den Begriffen komme ich bezüglich c++ noch garnicht klar

    Das ist merkwürdig. Du wagst dich in Serialisierung und Templates rein, kennst aber die Stream-Operatoren noch überhaupt nicht?



  • Nicht ganz, Skym0sh0, ich meinte so etwas:

    template<class T> void read (T& tm, std::string filename){
    
        std::ifstream myfile(filename.c_str());
    
        while(myfile){
            typename T::value_type value;
            if (myfile >> value)
              t.push_back(value);
        }
    }
    


  • Sone schrieb:

    Mit den Begriffen komme ich bezüglich c++ noch garnicht klar

    Das ist merkwürdig. Du wagst dich in Serialisierung und Templates rein, kennst aber die Stream-Operatoren noch überhaupt nicht?

    Da hast du schon recht. Ich bin mit der Situation auch alles andere als glücklich. Zum Lösen des Problems, muss ich aber scheinbar so vorgehen.



  • keinkollege schrieb:

    Nicht ganz, Skym0sh0, ich meinte so etwas:

    template<class T> void read (T& tm, std::string filename){
    
        std::ifstream myfile(filename.c_str());
    
        while(myfile){
            typename T::value_type value;
            if (myfile >> value)
              t.push_back(value);
        }
    }
    

    Zu diesem Code habe ich ein paar Fragen. Eben habe ich die Idee von Skym0sh0 (bzw. deine) in mein Programm übernommen. Die Werte werden nun übernommen. Nur der letzte Wert wurde doppelt gelesen.

    Bei diesem Code im Zitat, wird allerdings nur der 1. Wert (von 3) gelesen.

    1. was prüft while(myfile) ?
    2. was prüft if(myfile >> value) ?

    Sorry, wenn das alles etwas arg tapsig ist, aber ich muss mich gerade erst in C++ einlesen. Das Tempo ist dabei leider ungemütlich hoch.



  • 2. was prüft if(myfile >> value) ?

    Ob das Extrahieren von value erfolgreich war.

    1. was prüft while(myfile) ?

    Ob das fail - oder badbit gesetzt wurde.



  • keinkollege schrieb:

    Nicht ganz, Skym0sh0, ich meinte so etwas:

    template<class T> void read (T& tm, std::string filename){
    
        std::ifstream myfile(filename.c_str());
    
        while(myfile){
            typename T::value_type value;
            if (myfile >> value)
              t.push_back(value);
        }
    }
    

    Und jetzt schreiben wir das ganze auch noch in lesbar.

    template <typename Container>
    void read_file(std::string const& filename, Container& c)
    {
            std::ifstream is(filename);
    
            for(typename Container::value_type v; is >> v;)
                    c.push_back(std::move(v));
    }
    

    tada.



  • Kellerautomat schrieb:

    Und jetzt schreiben wir das ganze auch noch in lesbar.

    Es ging mir darum, mich möglichst an der Vorlage vom OP zu orientieren.

    Wenn du es mit mir aufnehmen willst, topp doch mal das hier:

    template <typename Container>
    void read_file(std::string const& filename, Container& c)
    {
      std::copy(std::istream_iterator<typename Container::value_type>{std::ifstream{filename}},
                std::istream_iterator<typename Container::value_type>{},
                std::back_inserter<typename Container::value_type>(c));
    }
    


  • template<typename Container>
    void read_file(std::string const &filename, Container &c) {
      c.insert(c.end(),
               std::istream_iterator<typename Container::value_type>(std::ifstream(filename.c_str())),
               std::istream_iterator<typename Container::value_type>());
    }
    


  • Wenn du es mit mir aufnehmen wills

    Keiner wollte es hier mit dir aufnehmen. 🙂
    Er wollte lediglich eine elegantere Lösung zeigen.


Anmelden zum Antworten