op>> + op<< + stream



  • Hi

    ich habe seit langer zeit mal wieder ein wenig programmiert und dabei kam ne bruch klasse raus(iwelche aufgaben irgend ner uni, die ich auf die schneller gefunden habe halt). nun habe ich aber bei op>> (und damit auch op<<) ein problem:

    1/1 als ausgabe sieht doof aus, also soll er nur 1 ausgeben. kein problem. aber eine 1 soll eben auch korrekt eingelesen werden...
    also hab ich mir folgendes zusammen gebaut:

    #include <iostream>
    
    template<char X>
    std::istream& skip_char(std::istream& s)
    {
    	if( !s )
    		return s;
    
    	auto next_char = s.get();
    	if( next_char == std::istream::traits_type::eof() )
    	{
    		s.setstate(std::ios::eofbit);
    		return s;
    	}
    
    	if( static_cast<char>(next_char) != X )
    	{
    		s.unget();
    		s.setstate(std::ios::failbit);
    	}
    
    	return s;
    }
    
    template<typename T>
    struct fraction
    {
    	fraction(const T& nominator = T(0), const T& denominator = T(1))
    	:	lhs_(nominator), rhs_(denominator)
    	{}
    
    	const T& nom() const { return lhs_; }
    	T& nom() { return lhs_; }
    
    	const T& denom() const { return rhs_; }
    	T& denom() { return rhs_; }
    
    private:
    	T lhs_;
    	T rhs_;
    };
    
    template<typename T>
    std::istream& operator>>(std::istream& s, fraction<T>& to_set)
    {
    	s >> to_set.nom();
    	if( !s )
    		return s;
    
    	s >> skip_char<'/'>;
    	if( !s )
    	{
    		s.clear(s.rdstate() & ~std::ios::failbit);
    		to_set.denom() = 1;
    	}
    	else
    		s >> to_set.denom();
    
    	return s;
    }
    template<typename T>
    std::ostream& operator<<(std::ostream& s, const fraction<T>& out)
    {
    	s << out.nom();
    	if( out.denom() != T(1) )
    		s << '/' << out.denom();
    	return s;
    }
    
    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <vector>
    
    int main()
    {
    	std::stringstream inss("1 1/13 4/17 4test");
    	std::ifstream in; in.set_rdbuf(inss.rdbuf());
    	std::stringstream out;
    
    	std::vector< my::fraction<int> > vec;
    
    	for( my::fraction<int> i; in >> i; )
    		vec.push_back(i);
    
    	std::string rest;
    	std::getline(in, rest);
    
    	for( auto &i : vec )
    		out << i << ' ';
    
    	std::cout << out.str() << rest << std::endl;
    	std::system("PAUSE");
    }
    

    der vector (und damit out) sieht schon mal ziemlich gut aus. das problem ist:
    - die implementierung erscheint mir äußerst frickelig
    - in der implementierung sind sicherlich einige (sonder-)fälle nicht bedacht
    - das "test" , welches durch getline in rest stehen sollte, ist nicht da

    -> hat jemand nen besseren vorschlag als lösung?
    -> hab ich bei dem getline nen denkfehler? oder wieso funktioniert das nicht? 😮

    danke


  • Mod

    #include <istream>
    #include <ostream>
    
    template<typename T>
    struct fraction
    {
    	fraction(const T& numerator = T(0), const T& denominator = T(1))
    	:   mNum(numerator), mDenom(denominator)
    	{}
    
    	const T& num() const { return mNum; }
    	T& num() { return mNum; }
    
    	const T& denom() const { return mDenom; }
    	T& denom() { return mDenom; }
    
    private:
    	T mNum;
    	T mDenom;
    };
    
    template<typename T>
    std::istream& operator>>(std::istream& s, fraction<T>& to_set)
    {
    	if (!(s >> to_set.num()))
    		return s;
    
    	s >> std::ws;
    
    	if (s.peek() == '/')
    	{
    		s.ignore();
    		s >> to_set.denom();
    	}
    	else
    		to_set.denom() = 1;
    
    	return s;
    }
    
    template<typename T>
    std::ostream& operator<<(std::ostream& s, const fraction<T>& out)
    {
    	s << out.num();
    
    	if (out.denom() != T(1))
    		s << '/' << out.denom();
    
    	return s;
    }
    
    #include <iostream>
    #include <sstream>
    
    int main()
    {
        std::stringstream inss("1 1/13 4/17 4test");
    
        for( fraction<int> i; inss >> i; )
            std::cout << i << '\n';
    }
    


  • oh. peek gibts da also - danke : D

    bin vorhin dann auch noch auf meinen getline-fail gekommen: da fehlt natürlich nen in.clear() davor

    PS: Beim Antworten wird (wie vor ~5 Jahren) noch immer kein html-decode auf den Thread-Titel angewendet...



  • T& num() { return mNum; }
    

    (sowie gleiches bei denom()) finde ich doch arg unsauber (dann kann man gleich public Member nehmen). Sollte der operator>> nicht besser friend der Klasse fraction sein (um dann direkt die Member zu setzen)?


  • Mod

    Sollte der operator>> nicht besser friend der Klasse fraction sein (um dann direkt die Member zu setzen)?

    😮 Warum denn das?



  • Was ist denn dann deine Alternative dazu?

    Eigentlich sollte m.E. so eine Klasse (bzw. Struktur) immutable sein - dann kann man jedoch den operator<<() nicht benutzen, sondern müsste eine Funktion

    fraction read(std::istream &istr)
    

    o.ä. erzeugen.



  • Arcoth schrieb:

    Sollte der operator>> nicht besser friend der Klasse fraction sein (um dann direkt die Member zu setzen)?

    🤡 🤡 😮 Warum denn das? 🤡 🤡

    Um die Attribute privat zu halten.


  • Mod

    Das war nicht sarkastisch gemeint. Ich dachte Th69 will total ueberfluessigerweise einen friend draus machen.

    Ich wusste ja nicht dass ihr die Struktur nach aussen hin immutable machen wollt - das halte ich naemlich nicht fuer sinnvoll. Warum?



  • Arcoth schrieb:

    Ich wusste ja nicht dass ihr die Struktur nach aussen hin immutable machen wollt - das halte ich naemlich nicht fuer sinnvoll. Warum?

    Naja, ein Setter dürfte es schon sein, getrennt vom Getter. Solange kein Bedarf an sowas ist, mache ich nicht auf. Und siehe da, in 4 Wochen gibt's immernoch keinen Setter. Irgendwann kommt man daher und kürzt die Brüche oder erzwingt, daß demom!=0 oder gar positiv. Das halte ich mir einfach offen.



  • @Arcoth: du hast trotzdem noch nicht meine Frage beantwortet - was ist deine Alternative zum friend (ohne Setter)?


  • Mod

    (sowie gleiches bei denom()) finde ich doch arg unsauber (dann kann man gleich public Member nehmen). Sollte der operator>> nicht besser friend der Klasse fraction sein (um dann direkt die Member zu setzen)?

    Wo steht da auch nur ansatzweise irgendwas von Immutability? Du hast nur darauf hingewiesen dass man lieber public Member anstelle von derartigen Funktionen nehmen kann. Solange man die Member von außen direkt verändern kann braucht man kein friend.


  • Mod

    volkard schrieb:

    Arcoth schrieb:

    Ich wusste ja nicht dass ihr die Struktur nach aussen hin immutable machen wollt - das halte ich naemlich nicht fuer sinnvoll. Warum?

    Naja, ein Setter dürfte es schon sein, getrennt vom Getter. Solange kein Bedarf an sowas ist, mache ich nicht auf. Und siehe da, in 4 Wochen gibt's immernoch keinen Setter. Irgendwann kommt man daher und kürzt die Brüche oder erzwingt, daß demom!=0 oder gar positiv. Das halte ich mir einfach offen.

    Man sollte aber schon wissen, ob man Brüche oder rationale Zahlen implementieren will...



  • Arcoth schrieb:

    (sowie gleiches bei denom()) finde ich doch arg unsauber (dann kann man gleich public Member nehmen). Sollte der operator>> nicht besser friend der Klasse fraction sein (um dann direkt die Member zu setzen)?

    Wo steht da auch nur ansatzweise irgendwas von Immutability? Du hast nur darauf hingewiesen dass man lieber public Member anstelle von derartigen Funktionen nehmen kann. Solange man die Member von außen direkt verändern kann braucht man kein friend.

    "(dann kann man gleich public Member nehmen)" war wie "(dann kann man sich auch gleich erschießen)". Das war doch keine Handlungsempfehlung! Trink erstmal nen Kaffee, ist noch sehr früh am Tag. 🤡



  • camper schrieb:

    volki schrieb:

    Naja, ein Setter dürfte es schon sein, getrennt vom Getter. Solange kein Bedarf an sowas ist, mache ich nicht auf. Und siehe da, in 4 Wochen gibt's immernoch keinen Setter. Irgendwann kommt man daher und kürzt die Brüche oder erzwingt, daß demom!=0 oder gar positiv. Das halte ich mir einfach offen.

    Man sollte aber schon wissen, ob man Brüche oder rationale Zahlen implementieren will...

    Ach, das halte ich mir vielleicht am besten auch noch offen. 🙂



  • @Volkard: genau so war es gemeint - irgendwie kommt mein Sarkasmus wohl nicht immer an!?


Anmelden zum Antworten