operator << überladen



  • Hallo,
    Ich habe den operator<< überladen:

    class Exception {
    	const Exception& operator<< (std::string val) {
    		Parameter.push_back(val);
    		return(*this);
    	}
    };
    

    Jetzt habe ich folgende Zeile:

    throw Exception(ExceptionType::IndexOutOfRange) << index << val
    

    Wirft diese Zeile eine Exception(ExceptionType::IndexOutOfRange), in die index und val eingefügt wurden? Oder verstehe ich etwas daran falsch?

    Danke schon im Voraus.

    mfg
    Mr X



  • Ja, sollte so gehen. Der Ausdruck

    Exception(ExceptionType::IndexOutOfRange)
    

    erzeugt ein temporäres Objekt, auf den operator<< angewandt wird. Der Operator gibt wiederum ein temporäres Objekt zurück. Schlussendlich wirfst du das Resultat des gesamten Ausdrucks, also die Verkettung aller Einfügungen.

    P.S.: Eine Alternative wäre operator() . Kann ja sein, dass dir das syntaktisch besser gefällt:

    throw Exception(ExceptionType::IndexOutOfRange)(index)(val);
    


  • Ok, Danke.

    Dann habe ich es ja geschafft, eine einfache Syntax für meine Klasse zu erzeugen.



  • Ich habe noch was reineditiert, das auch die Syntax betrifft. 😉

    Ach ja, und ich würde Const-Referenz-Parameter nehmen. Was mir auch noch aufgefallen ist: Der Operator sollte eine Referenz auf Non- const zurückgeben, sonst kann das Resultat nicht mehr verändert werden.



  • Der operator<< gefällt mir irgendwie besser (STL-Stream-Klassen ähnlich).

    Ich hab das jetzt so verändert:

    class Exception {
        Exception& operator<< (const std::string& val) {
            Parameter.push_back(val);
            return(*this);
        }
    };
    

    Ich musste das const beim Rückgabetyp entfernen, weil die Referenz nicht const sein darf, da ich auf sie ja den nicht-konstanten operator<< ausführe.



  • Nur so als genereller Hinweis:
    Bei Exception-Klassen solltest du aber vorsichtig sein bzgl. Memory-Allocation, sonst kriegst du evtl. darin dann eine OutOfMemory-Exception beim 'vector::push_back'.



  • eventuell="quasi nie, und wenn ja, war eh bereits alles verloren".

    Ein Nachteil an der Klasse ist meiner Meinung nach, dass sie nicht von std::exception abgeleitet ist. Aber vielleicht ist das auch nur ein Codeausschnitt und im original ist sie das 🙂



  • throw Exception(ExceptionType::IndexOutOfRange) << index << val;
    

    sieht aber leicht eklig aus 😛
    wenn überhaupt dann würde ich so was hier schreiben wollen:

    Exception e(ExceptionType::IndexOutOfRange);
    e << index << val;
    throw e;
    

    den operator<< würde ich außerhalb der klasse definieren und die würde in etwa so aussehen:

    struct Exception : std::runtime_error
    {
    /*CTOR und ggf. what() fehlt noch*/
    
      template<typename T>
      void to_add(const T& to_add)
      {
        std::stringstream ss;
        ss << to_add;
        to_add(ss.str());
      }
    
      void to_add(const std::string& to_add)
      {
        data.push_back(to_add);
      }
    
    private:
      std::vector<std::string> data;
    };
    
    template<typename T>
    Exception& (Exception& these, const T& to_add)
    {
      Exception.Add(to_add);
      return these;
    }
    
    void test()
    {
      int index;
      double val;
    
      std::cin >> index;
      val = 3.14159265*index;
    
      if(index > 5)
      {
        Exception e(ExceptionType::IndexOutOfRange);
        e << index << val;
        throw e;
      }
    }
    
    int main()
    {
      for(;;)
      {
        try
        {
          foo();
        }
        catch(Exception& e)
        {
          std::cout << "cought: " << e.what() << std::endl;
        }
      }
    }
    

    Wenn du mit der Exception auch bad_alloc signalisieren können möchtest, müsstest du im to_add(std::string) testen, ob dein enum bad_alloc sagt und wenn ja, dann einfach nichts machen. (aber eigtl wirst du ja bei bad_alloc kaum noch daten mitgeben wollen?!)
    Oder du schreibst dir nen Allokator, der Platz aufm Stack nimmt - iwo hier gibts nen STL-Allocator-Thread, dort hab ich heut früh oder so nen Bsp. gepostet, wie man so was machen könnte - du müsstest ihn nur etwas anpassen oder im ctor auch gleich nen reserve machen...
    dann hast du nur noch mit dem stringstream nen Problem - dem kannst du aber imho auch keinen allocator mitgeben...

    den enum-ansatz würd ich btw auch nicht nehmen sondern mit templates arbeiten - dann könnte man den bad_alloc-Fall entsprechend spezialisieren...

    bb



  • unskilled, du hast etwas wichtiges (operator <<) vergessen:

    template<typename T> 
    Exception& operator<<(Exception& these, const T& to_add) 
    { 
      Exception.Add(to_add); 
      return these; 
    }
    

    Oder meintest du, weil es ja im Titel des Beitrags steht, brauchst du es nicht noch mal hinschreiben? 🙂

    P.S: what is "cought:"???



  • Th69 schrieb:

    P.S: what is "cought:"???

    Ein Schreibfehler 😛
    -> catch -> caught
    Etwas (ab)fangen, in dem Fall eine Exception.



  • 1.:

    template<typename T> 
    Exception& (Exception& these, const T& to_add) 
    { 
      Exception.Add(to_add); 
      return these; 
    }
    

    hier fehlt einfach noch operator<< - sry^^
    so macht das stück hier natürlich nicht all zu viel sinn 😉

    2.:
    wollt noch was zum knobeln übriglassen ;o)

    bb


Anmelden zum Antworten