void foo(int, int, int, int)



  • Da in meinem Algorithmus fast nur int Typen vorkommen und Parameterlisten schon mal 3-5 int Parameter haben ist mir durch versehentliches Vertauschen von Parametern beim Aufruf einer solchen Funktion ein böser Fehler unterlaufen:

    // Define Foo()
    void Foo(int color, int file, int rank) {
      // Implementation...
    }
    
    // Call Foo()
    foo(file, color, rank);  // Hard to find bug
    

    Eine Möglichkeit wäre ints durch enums zu ersetzen, dann würde der Compiler den Fehler schon finden.

    // Define int Types as enum
    enum Color {};
    enum File {};
    enum Rank {};
    
    // Define Foo()
    void Foo(Color color, File file, Rank rank) {
      // Implementation...
    }
    
    // Call Foo()
    foo(file, color, rank);  // Produces compiler warning
    

    Allerdings habe ich dann schon das nächste Problem, da man mit enums wohl nicht rechnen kann ohne diese zu überladen 😞

    Welche vernünftige Möglichkeiten gibt es noch, solche Fehler zu vermeiden?

    PS:
    Verwende schon Bereichsprüfungen (assert()), aber die schlagen auch nicht immer an.



  • Tomahawk schrieb:

    Welche vernünftige Möglichkeiten gibt es noch, solche Fehler zu vermeiden?

    Bastel dir eben entsprechende Typen, d.h. schreib dir eine Klasse File, Color, Rank, ...



  • Vielleicht ein struct, wenn die Daten logisch zusammen gehoeren und dann uebergibst du nur das Struct?



  • Ruvi schrieb:

    Vielleicht ein struct, wenn die Daten logisch zusammen gehoeren und dann uebergibst du nur das Struct?

    Bei einem struct müssen aber auch die benötigten Integer Operationen überladen werden, falls man nicht sowas haben will:

    void Foo(Color color, File file, Rank rank) {
      Square sq;
      sq.data = file.data + (rank.data << 3);  // Ugly
    }
    

  • Mod

    Vertauschen von Parametern beim Aufruf einer solchen Funktion ein böser Fehler unterlaufen:

    Die einfachste und direkteste Loesung: Pass einfach auf, welche Parameter du angibst.



  • Tomahawk schrieb:

    Ruvi schrieb:

    Vielleicht ein struct, wenn die Daten logisch zusammen gehoeren und dann uebergibst du nur das Struct?

    Bei einem struct müssen aber auch die benötigten Integer Operationen überladen werden, falls man nicht sowas haben will:

    void Foo(Color color, File file, Rank rank) {
      Square sq;
      sq.data = file.data + (rank.data << 3);  // Ugly
    }
    

    dann mach halt einen impliziten konvertierungsoperator...



  • Tomahawk schrieb:

    Ruvi schrieb:

    Vielleicht ein struct, wenn die Daten logisch zusammen gehoeren und dann uebergibst du nur das Struct?

    Bei einem struct müssen aber auch die benötigten Integer Operationen überladen werden, falls man nicht sowas haben will:

    void Foo(Color color, File file, Rank rank) {
      Square sq;
      sq.data = file.data + (rank.data << 3);  // Ugly
    }
    

    Ich dachte eigentlich eher an ein einzelnes struct.
    Du schreibst die Sachen nacheinander auf einen Zettel und uebergibst dann den Zettel. Die Wahrscheinlichkeit sich da zu vertippen sollte gen null gehen.

    struct infos {
    
    int color;
    int file;
    int rank;
    
    };
    
    sq.data = infos.color +  (infos.rank << 3);
    


  • Wie schon dot gesagt hat, schreib dir eigene Typen. Du kannst ja darauf achten, nicht sämtliche Operatoren zu duplizieren. Boost.Operators könnte dabei auch helfen.

    Wenn sich die Typen wirklich nur durch einen "Tag" unterscheiden, kannst du auch sowas machen:

    template <typename Tag>
    class Value // besseren Namen finden
    {
        ...
    };
    
    struct ColorTag {};
    struct RankTag {};
    
    typedef Value<ColorTag> Color;
    typedef Value<RankTag> Rank;
    

    Du kannst das auch mit Enums kombinieren, um typsichere Werte (statt Magic Numbers) zu haben.


Log in to reply