wie funktioniert equal()



  • Progressive schrieb:

    Also zum einen ist es scheinbar egal, auf welchen String er vergleichen soll. Selbst wenn der String nicht vorhanden ist, geht er in die Schleife rein.

    if ist keine Schleife.

    Die Bedingung dürfte nie true sein, da du immer verschieden lange Strings vergleichst. Allerdings erzeugts du hier undefiniertes Verhalten, da du über das Ende des zweiten Strings hinaus liest.
    Ich würde

    if(database_line.substr(0,database_line_begin.size()) == database_line_begin)
    

    vorschlagen (ungetestet!).

    Progressive schrieb:

    Andererseits kann ich, wenn ich mit getline innerhalb der Schleife herumspiele, durchaus den Output steuern. Das mag sinnig wirken aber dennoch nicht gezielt.
    Bestes Resultat war bislang die gewünschte Zeile + die vorige. Aber nie die einzelne. Ich werde da nicht schlau draus..

    Ich habe keine Ahnung, was du damit sagen willst.



  • manni66 schrieb:

    Progressive schrieb:

    Also zum einen ist es scheinbar egal, auf welchen String er vergleichen soll. Selbst wenn der String nicht vorhanden ist, geht er in die Schleife rein.

    if ist keine Schleife.

    Die Bedingung dürfte nie true sein, da du immer verschieden lange Strings vergleichst. Allerdings erzeugts du hier undefiniertes Verhalten, da du über das Ende des zweiten Strings hinaus liest.
    Ich würde

    if(database_line.substr(0,database_line_begin.size()) == database_line_begin)
    

    vorschlagen (ungetestet!).

    Ja, nicht Schleife, falscher Ausdruck, meinte den Programmblock der if-Bedingung.
    Ok, danke, werde ich gleich mal versuchen! Dessen ungeachtet, aus Verständniszwecken: Der zweite String, also "string database_line_begin = "fit"" hat doch aber ein definiertes Ende ?

    Torsten Robitzki schrieb:

    std::equal() geht davon aus, dass die zweite Sequence (der dritte Parameter) genau so lang, oder länger ist als die erste Sequence (die ersten beiden Parameter). Wenn immer database_line länger ist als database_line_begin, hast Du schon undefined behavior. Guck Dir mal an, wie regular expressions funktionieren, mit denen sollte Dein Problem mit einem Drei-Zeiler lösbar sein.

    mfg Torsten

    Also wenn die zweite Sequenz gleich lang oder länger sein soll, kann ich ja einfach die Reihenfolge ändern: if(equal(database_line_begin.begin(), database_line_begin.end(), database_line.begin()))
    Das funktioniert sogar 😮 🙄 😮 🙄 😮 🙄
    Werde mir diese regular expressions dennoch mal angucken! Vielen Dank soweit!

    Ich bin nirgends darauf gestoßen, dass der zweite String gleich lang/länger sein muss..
    Gibt es ein umfangreiches aber übersichtliches Handbuch über alle C++-Befehle, das ihr empfehlen könnt ?



  • Progressive schrieb:

    Gibt es ein umfangreiches aber übersichtliches Handbuch über alle C++-Befehle, das ihr empfehlen könnt ?

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
    http://en.cppreference.com

    Progressive schrieb:

    Dessen ungeachtet, aus Verständniszwecken: Der zweite String, also "string database_line_begin = "fit"" hat doch aber ein definiertes Ende ?

    Ja, aber woher weiß equal, wo das Ende ist?

    http://en.cppreference.com/w/cpp/algorithm/equal schrieb:

    Returns true if the range [first1, last1) is equal to the range [first2, first2 + (last1 - first1)), and false otherwise

    Es wird also bis first2 + (last1 - first1) gelesen, d.h. meistens zu weit.



  • Progressive schrieb:

    Werde mir diese regular expressions dennoch mal angucken! Vielen Dank soweit!

    'regular expressions' wären hier IMHO Kanonen auf Spatzen. Letzlich brauchst Du nur auf "fit data:" abzufragen - etwa so:

    #include <fstream>
    #include <iostream>
    #include <string>
    #include <limits>
    #include <vector>
    
    std::istream& skipline( std::istream& in )
    {
        return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' );
    }
    
    struct Fit
    {
        int rad, grid, grid_pos, M;
        double temp, Ubias, Id, proM_dM_dV;
    };
    
    std::istream& operator>>( std::istream& in, Fit& e )
    {   // SN Temp rad grid grid_pos M Ubias Id 1/M_dM/dV
        std::string SN;  // .. brauchst Du das?      
        return in >> SN >> e.temp >> e.rad >> e.grid >> e.grid_pos >> e.M >> e.Ubias >> e.Id >> e.proM_dM_dV;
    }
    
    int main()
    {
        using namespace std;
        vector< Fit > all_fits;
        ifstream database("Test.txt");
        if( !database.is_open() )
        {
            cerr << "Fehler beim Oeffnen der Datei" << endl;
            return 0;
        }
        for( Fit e; database; )
        {
            for( string token; database >> token && (token != "fit" || (database >> token && token != "data:") )
                ; database >> skipline )
                ;
            for( auto i=0; i<2; ++i )
                database >> skipline;
            if( database >> e )
                all_fits.push_back( e );
        }
        cout << all_fits.size() << " Eintraege gelesen" << endl;
        return 0;
    }
    

    Gruß
    Werner



  • manni66 schrieb:

    Progressive schrieb:

    Gibt es ein umfangreiches aber übersichtliches Handbuch über alle C++-Befehle, das ihr empfehlen könnt ?

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
    http://en.cppreference.com

    Danke!

    manni66 schrieb:

    Progressive schrieb:

    Dessen ungeachtet, aus Verständniszwecken: Der zweite String, also "string database_line_begin = "fit"" hat doch aber ein definiertes Ende ?

    Ja, aber woher weiß equal, wo das Ende ist?

    http://en.cppreference.com/w/cpp/algorithm/equal schrieb:

    Returns true if the range [first1, last1) is equal to the range [first2, first2 + (last1 - first1)), and false otherwise

    Es wird also bis first2 + (last1 - first1) gelesen, d.h. meistens zu weit.

    Wenn man einen String definiert, dann ist das Ende doch vorgegeben. Warum wird z.B. "string str = "Content"; nicht ein entsprechendes Zeichen nach dem String-Inhalt gesetzt ?

    Danke, Werner!
    Es funktioniert aber das muss ich erstmal verstehen. Hat insofern den Vorteil, als dass da eh viel auftaucht, was ich mir ohnehin aneignen muss 🙂

    Bedeutet:

    for( string token; database >> token && (token != "fit" || (database >> token && token != "data:") )
                ; database >> skipline )
                ;
            for( auto i=0; i<2; ++i )
                database >> skipline;
            if( database >> e )
                all_fits.push_back( e );
    

    dass solange aus der Datei gelesen wird, bis "fit" oder "data" auftauchen, die nächsten zwei Zeilen verworfen werden und die Zeile darauf dann in den vector geschrieben wird ?
    Müsste es dann aber nicht token == "fit", anstelle von token != "fit" heißen ?



  • Wie kann ich mir den Inhalt des Vektors eigentlich ansehen ?

    Mittels "cout << database_vector[0] << endl;" funktioniert das irgendwie nicht.



  • Eigentlich brauchst du nur zu checken, ob eine Zeile mit einer Zahl beginnt.
    Ungefähr so:

    #include <iostream>
    #include <fstream>
    #include <limits>
    #include <cctype>
    
    int main(){
        std::ifstream stream{"f"};
        std::string line;
    
        while(stream){
            if(std::isdigit(stream.peek())){
                std::getline(stream, line);
                std::cout << line << '\n';
                // oder einfach weiter mit dem Stream parsen
            }
    
            else
                stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
    }
    


  • Progressive schrieb:

    Wenn man einen String definiert, dann ist das Ende doch vorgegeben. Warum wird z.B. "string str = "Content"; nicht ein entsprechendes Zeichen nach dem String-Inhalt gesetzt ?

    Woher weiß equal, dass es ein String ist?
    Woher weiß equal, welches Zeichen am Ende steht?
    Welches Zeichen soll einen std::vector<int> beenden?
    Welches Zeichen soll einen std::vector<Foo> beenden?



  • einfach schrieb:

    Eigentlich brauchst du nur zu checken, ob eine Zeile mit einer Zahl beginnt.
    Ungefähr so:

    #include <iostream>
    #include <fstream>
    #include <limits>
    #include <cctype>
    
    int main(){
        std::ifstream stream{"f"};
        std::string line;
    
        while(stream){
            if(std::isdigit(stream.peek())){
                std::getline(stream, line);
                std::cout << line << '\n';
                // oder einfach weiter mit dem Stream parsen
            }
    
            else
                stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
    }
    

    Gefällt mir auch!

    Habe es mit dem Drumherum von Werner kombiniert:

    (...)for(dataset parameter; database;)									
    	{
    		if(isdigit(database.peek()))	
    		{
    			if(database >> parameter) database_vector.push_back(parameter);		
    		}		
    		else database.ignore(std::numeric_limits<std::streamsize>::max(), '\n');	
    	}(...)
    

    manni66 schrieb:

    Progressive schrieb:

    Wenn man einen String definiert, dann ist das Ende doch vorgegeben. Warum wird z.B. "string str = "Content"; nicht ein entsprechendes Zeichen nach dem String-Inhalt gesetzt ?

    Woher weiß equal, dass es ein String ist?
    Woher weiß equal, welches Zeichen am Ende steht?
    Welches Zeichen soll einen std::vector<int> beenden?
    Welches Zeichen soll einen std::vector<Foo> beenden?

    Weil es als solches definiert wurde ?
    Wenn es eines am Ende eines Strings gäbe, könnte es darauf prüfen.
    Das liegt nicht in meiner Entscheidungsgewalt :p



  • Wie gebe ich denn den Vektor nun aus ?

    Ich habe jetzt:

    istream& skipline(istream& in)	
    {
        return in.ignore(numeric_limits<streamsize>::max(), '\n' );		
    }
    
    struct dataset		
    {
        int rad, grid, grid_pos, M;
        double temp, Ubias, Id, proM_dM_dV;
    };
    
    istream& operator>>(istream& in, dataset& parameter)	
    { 
        string SN;      
        return in >> SN >> parameter.temp >> parameter.rad >> parameter.grid >> parameter.grid_pos >> parameter.M >> parameter.Ubias >> parameter.Id >> parameter.proM_dM_dV;	
    }
    
    int compare(int start = 378, int ignore_matched_apds = 1, int select_grids = 0, const char *inputfile="Test.txt", const char *apds_glued_file="apds_glued.txt", const char *grids_file="grids.txt", const char *outputfile="apds_matched.txt", const char *simple_outputfile="simple_apds_matched.txt")
    {    
    	ifstream database(inputfile), glued_apds, grids;				
    	ofstream output(outputfile), simple_output(simple_outputfile);	
    	vector<dataset> database_vector;		
    
    	if(!database)
    	{
    		cerr << "File \"" << inputfile << "\" not found\n" << endl; 
    		return(-1);
    	}
    	else cout << "Open \"" << inputfile << "\" as database" << endl;
    	for(dataset parameter; database;)		
    	{
    		if(isdigit(database.peek()))		
    		{
    			if(database >> parameter) database_vector.push_back(parameter);		
    		}		
    		else database.ignore(std::numeric_limits<std::streamsize>::max(), '\n');	
    	}
    	if(database_vector.size()==0)
    	{
    		cout << "Reading from \"" << inputfile << "\" failed. No parameters found." << endl; 
    		return(-1);
    	}
    	cout << database_vector.size() << " entries read out" << endl;
    	for(std::vector<dataset>::iterator it = database_vector.begin(); it != database_vector.end(); it++) cout << *it << endl;	
    	return 0;
    }
    

    Aber das funktioniert nicht 😕



  • Analog zum Einlesen mittels >> einen Ausgabe-Operator << definieren:

    ostream& operator<<(ostream& out, const dataset& parameter)
    


  • Progressive schrieb:

    manni66 schrieb:

    Progressive schrieb:

    Wenn man einen String definiert, dann ist das Ende doch vorgegeben. Warum wird z.B. "string str = "Content"; nicht ein entsprechendes Zeichen nach dem String-Inhalt gesetzt ?

    Woher weiß equal, dass es ein String ist?
    Woher weiß equal, welches Zeichen am Ende steht?
    Welches Zeichen soll einen std::vector<int> beenden?
    Welches Zeichen soll einen std::vector<Foo> beenden?

    Weil es als solches definiert wurde ?

    Du übergibst keinen String sondern einen Iterator.



  • Th69 schrieb:

    Analog zum Einlesen mittels >> einen Ausgabe-Operator << definieren:

    ostream& operator<<(ostream& out, const dataset& parameter)
    

    Hi, habe in der Zwischenzeit generell mich mal etwas über C++ eingelesen. Leider traf ich nie auf den o.a. Fall bzw. konnte ihn darauf abstrahieren.

    Was bedeutet denn ostream& operator<<(ostream& out, const dataset& parameter) ?
    Bei http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt steht std::basic_ostream::operator<< Inserts data into the stream.

    Wo/wie wirkt denn out ? Meinem Verständnis nach habe ich bislang zwei streams: Jeweils einen für die Dateieinlese und einen für die Dateiauslese (in meinem Beispiel database und output). Was macht daher out und in bzw. was macht der operator konkret ?

    Und was ist "parameter" ? Definiert wurde es ja glaube als Variable vom Typ dataset. Aber warum ?



  • Wie kommt es, daß du den Eingabe-Operator >> verwendest (und zu verstehen scheinst), aber den gegenteiligen Ausgabe-Operator << nicht?

    Stichwort: Überladung von I/O Stream Operatoren, s. z.B. Overloading the I/O operators

    PS: Im Thread Ausgabe von Objekten mittels for-Schleife und Methoden gibt es auch eine Erklärung zum <<-Operator (von "HarteWare").



  • Th69 schrieb:

    Wie kommt es, daß du den Eingabe-Operator >> verwendest (und zu verstehen scheinst), aber den gegenteiligen Ausgabe-Operator << nicht?

    Weil ich den dato lediglich analog definiert habe. Ich bin eher jemand, bei dem das Verständnis mit dem Ausprobieren kommt. Aber an den Punkt gelange ich bzgl. diesen streams bislang nicht (da man da im Vorfeld scheinbar doch mehr verstanden haben muss ^^). Ohne Klasse u.ä. lediglich Dateien einzulesen usw. ist klar, aber da kommt man ja auch ohne den <<operator aus.

    Th69 schrieb:

    Stichwort: Überladung von I/O Stream Operatoren, s. z.B. Overloading the I/O operators

    PS: Im Thread Ausgabe von Objekten mittels for-Schleife und Methoden gibt es auch eine Erklärung zum <<-Operator (von "HarteWare").

    Danke für die Links! Das hat mir vom Verständnis schonmal geholfen, ich probiere das mal umzusetzen 🙂



  • So, habe jetzt alles und es funktioniert sogar.
    Verstehe es aber trotzdem nicht 😃 🙄

    Ich habe Folgendes:

    //main.cpp

    #include <fstream>
    #include <iostream>
    #include <string>
    #include <limits>
    #include <vector>
    #include <algorithm>
    #include "APD.h"
    
    using namespace std;
    
    int main(int argc,char *argv[])
    {   
    const char *INPUTFILE="Test.txt"; 
    ifstream input(INPUTFILE);
    APD apd(input);
    apd.print();
    }
    

    //APD.h

    #ifndef APD_H
    #define APD_H
    #include <iostream>
    
    class APD
    {
    	private:
    		int m_SN;
    		double m_temperature;
    		int m_rad;
    		int m_grid;
    		int m_grid_pos;
    		double m_M;
    		double m_UBias;
    		double m_Id;
    		double m_dM;
    
    	public:
    		ostream& operator<<(ostream& out);	
    		friend istream& operator>> (istream& in, APD& apd);						
    
    		APD();	
    		APD(ifstream& input);										
    
    		~APD();	
    };
    #endif
    

    //APD.cpp

    #include <string>
    #include <limits>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <fstream>
    #include "APD.h"
    
    using namespace std;
    
    	APD::APD()
    	{
    		m_SN=0.; 
    		m_temperature=0; 
    		m_rad=0.; 
    		m_grid=0.; 
    		m_grid_pos=0.; 
    		m_M=0; 
    		m_UBias=0; 
    		m_Id=0; 
    		m_dM=0;
    	}
    
    	APD::~APD(){}	
    
    	APD::APD(ifstream& input)										
    	{
    		while(!input.eof()) 
    		{			
    			if(isdigit(input.peek()))							
    			{
    				break;					
    			}		
    			else input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');			
    		}
    		input >> m_SN >> m_temperature >> m_rad >> m_grid >> m_grid_pos >> m_M >> m_UBias >> m_Id >> m_dM;
    	}
    
    	istream& operator>> (istream& in, APD& apd)		
    	{     
    		while(in) 
    		{			
    			if(isdigit(in.peek()))								
    			{
    				break;					
    			}		
    			else in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');			
    		}
    		in >> apd.m_SN >> apd.m_temperature >> apd.m_rad >> apd.m_grid >> apd.m_grid_pos >> apd.m_M >> apd.m_UBias >> apd.m_Id >> apd.m_dM;	
    		return in;
    	}
    
    	ostream& APD::operator<<(ostream& out) 							
    	{     
    		out << m_SN << m_temperature << m_rad << m_grid << m_grid_pos << m_M << m_UBias << m_Id << m_dM;	
    		return out;
    	}						
    
    	void APD::print() const
    	{
    		cout<<"*************************************"<<endl;
    		cout<<"SN	: "<<m_SN<<endl;
    		cout<<"Grid	: "<<m_grid<<endl;
    		cout<<"Grid Pos	: "<<m_grid_pos<<endl;
    		cout<<"*************************************"<<endl;
    	}
    

    Ich verstehe nicht, wofür ich ostream& operator<<(ostream& out) und friend istream& operator>> (istream& in, APD& apd) benötige.



  • Progressive schrieb:

    So, habe jetzt alles und es funktioniert sogar.
    Verstehe es aber trotzdem nicht 😃 🙄

    [...]

    Ich verstehe nicht, wofür ich ostream& operator<<(ostream& out) und friend istream& operator>> (istream& in, APD& apd) benötige.

    Also: Deine print-Funktion gibt immer auf der Standardausgabe Daten aus ( cout << ... ). Normalerweise möchte man sowas allgemein halten, dass man auch zum Beispiel in eine Datei schreiben könnte. Du kannst deinem print also einen Parameter vom Typ ostream& spendieren und statt cout den übergebenen Stream verwenden.

    Den opereator<< brauchst du, damit du in deinem Hauptprogramm sowas schreiben kannst:

    APD apd(input);
    // statt: apd.print();
    std::cout << apd << '\n';
    

    Dazu definiere den operator<< analog zu operator>>, also NICHT so wie du es gemacht hast, sondern definiere ihn analog AUSSERHALB der Klasse und gib ihm ostream& und const APD& als Parameter. Darin schreibst du dann mit << auf den ostream, den du am Ende returnst. Oder besser, rufe in dem operator<< einfach apd.print(os) auf, nachdem du dem print das ostream-Argument hinzugefügt hast.



  • Ok, danke!
    Warum soll ich die <<,>> Operatoren denn außerhalb der Klasse definieren bzw. wo denn ? In main ?

    Mit analog meinst du:

    ostream& operator<<(ostream& out, const APD&);	
    istream& operator>>(istream& in, const APD&);
    

    oder

    ostream& operator<<(ostream& out, APD& apd);	
    istream& operator>>(istream& in, APD& apd);
    

    ?

    Ich verstehe den zweiten Parameter irgendwie nicht. Was bedeutet "APD&" und was "APD& apd" ? Ich stehe da echt auf dem Schlauch, dabei habe ich schon einiges gelesen.. 😞



  • Progressive schrieb:

    Ok, danke!
    Warum soll ich die <<,>> Operatoren denn außerhalb der Klasse definieren bzw. wo denn ?

    Du sollst das für << genauso machen wie >> (das schrieb ich doch)!

    Guck doch mal, was du geschrieben hast in der cpp-Datei:

    istream& operator>> (istream& in, APD& apd)
    ostream& APD::operator<<(ostream& out)
    

    Fällt dir da ein Unterschied auf? << ist in der Klasse, >> ist nicht in der Klasse. Im Header hast du einmal den >> als Friend markiert. Wenn du über print gehst, brauchst du << nicht einmal als friend markieren.

    Die Signatur von << sollte so sein:

    ostream& APD::operator<<(ostream& out, const APD& apd)
    

    Mit analog meinst du:

    ostream& operator<<(ostream& out, const APD&);	
    istream& operator>>(istream& in, const APD&);
    

    oder

    ostream& operator<<(ostream& out, APD& apd);	
    istream& operator>>(istream& in, APD& apd);
    

    Natürlich die Version mit const! Du willst doch nicht, dass eine Ausgabe das Objekt ändern kann.

    Ich verstehe den zweiten Parameter irgendwie nicht. Was bedeutet "APD&" und was "APD& apd" ?

    Das ist doch dieselbe Signatur. Einmal vergibst du einen Namen, einmal nicht.
    APD&: es wird ein Parameter vom Typ Referenz auf APD übergeben. Ein Name wird noch nicht vergeben.
    APD& apd: es wird ein Parameter vom Typ Referenz auf APD übergeben, welcher den Namen "apd" hat (wenn du keinen Namen vergibst, kannst du den Wert nicht benutzen - aber wenn du nur die Funktion deklarierst aber nicht definierst, brauchst du den Namen noch nicht).



  • Ich schrieb mist:

    ostream& APD::operator<<(ostream& out, const APD& apd)
    

    meinte natürlich:

    ostream& operator<<(ostream& out, const APD& apd)
    

    Ohne das APD::


Anmelden zum Antworten