Compilerfehler künstlich erzeugen



  • Hallo,

    ich habe ein Konstrukt programmiert, dass ungefähr folgende Struktur hat:

    template<int AnzahlRaeder, int AnzahlHinterraeder, int Modus>
    class Fahrzeug
    {
        public:
             Auto()
             {
                //Hier wäre eine Überprüfung notwendig, ob das Objekt so überhaupt erzeugbar ist.
             }
    
        private:
    
    }
    

    Insgesamt habe ich hierzu zwei Wünsche oder Ideen, weiß aber nicht, ob es überhaupt möglich ist.

    Zum einen ist klar, dass ein Fahrzeug welches mehr Hinterräder hat als Räder insgesamt keinen Sinn ergibt. Da diese Angaben schon zur Compilezeit feststehen, meine Frage: Kann man einen Compilerfehler erzeugen, wenn folgende Bedingung erfüllt ist:

    AnzahlHinterraeder > AnzahlRaeder
    

    Zum anderen wird ein Modus dort oben angegeben. Diesen möchte ich über Bitflags setzten. Beispielsweise wie folgt:

    Bit:n, Bit:n-1, ..., Bit:1, Bit:0

    Bit:1 Handelt es sich um ein Auto ja/nein
    Bit:2 Handelt es sich um ein Sportwagen ja/nein
    Bit:3 ...

    Meine Idee ist, per Enum Werte festlegen:

    enum auto_eigenschaften{ISTAUTO = 1, ISTSPORTWAGEN = 2, ISTEIGENSCHAFTDREI = 4, ISTEIGENSCHAFTVIER = 7};
    

    und schließend überprüfen ob diese Eigenschaften zusammen Sinn ergeben. Dieses könnte dann per Bitmasken passieren.

    Und auch hier wie schon oben, wenn es keinen Sinn gibt, Compilerfehler.

    Wie immer bin ich über jeden Tipp dankbar.

    Viele Grüße
    MM

    PS: Könnt ihr mir einen Tip geben, wo man so etwas am besten nachschlagen kann oder googlen kann? Leider viel mir kein sinniger Begriff ein.



  • Such mal nach static_assert .



  • Registrierter Troll schrieb:

    Such mal nach static_assert .

    Ist das Teil des Standards?



  • #pragma error(bla)
    

    Meine ich schonmal irgendwo gelesen zu haben.

    Gruß


  • Mod

    uzuzuzuzuz schrieb:

    Registrierter Troll schrieb:

    Such mal nach static_assert .

    Ist das Teil des Standards?

    Noch nicht. Ist aber für C++0x vorgeschlagen und wird von vielen Compilern schon heute verstanden.



  • uzuzuzuzuz schrieb:

    Registrierter Troll schrieb:

    Such mal nach static_assert .

    Ist das Teil des Standards?

    Das weiß ich auch nicht, aber der S_StaticAssert für boolsche Bedingungen ist schnell geschrieben

    template <bool condition>
    struct S_StaticAssert
    {};
    
    template<>
    struct S_StaticAssert<true>
    {
    	static void check(){;}
    };
    
    S_StaticAssert<(1 < 2)>::check(); //kompiliert;
    S_StaticAssert<(1 > 2)>::check(); //kompiliert nicht;
    

    Greets
    Tobi _logoff



  • Sowohl die Loki-Bibliothek als auch Boost haben ein static_assert bzw. ein BOOST_STATIC_ASSERT - und beide sind standardkonform.



  • Zuerst vielen Dank 🙂

    Mmmh,

    was genau ist nach derzeitigem Standard nun erlaubt? Bei

    #include <boost/static_assert.hpp>
    

    findet der die Datei nicht.

    Bzw. der neue Standard brauch doch noch ein 3/4 Jahr, oder? Bei heise.de hab ich so etwas gelesen.

    Viele Grüße
    MM


  • Mod

    MrMilk schrieb:

    Zuerst vielen Dank 🙂

    Mmmh,

    was genau ist nach derzeitigem Standard nun erlaubt? Bei

    #include <boost/static_assert.hpp>
    

    findet der die Datei nicht.

    Bzw. der neue Standard brauch doch noch ein 3/4 Jahr, oder? Bei heise.de hab ich so etwas gelesen.

    Viele Grüße
    MM

    Das Schlüsselwort "static_assert" kommt erst mit dem neuen Standard. Boost ist eine externe Bibliothek, die auf sehr vielen Systemen verfügbar ist und ein äquivalentes Konstrukt bietet. Dieses Konstrukt ist aber mit Mitteln aus dem (jetzigen) C++ Standard aufgebaut - es dürfte sich um das von Tobi_logoff gezeigte oder etwas Ähnliches handeln.
    Du kannst also entweder
    1.) gucken, ob dein Compiler schon static_assert kennt
    2.) die Boost Bibliothek installieren und benutzen
    3.) den entsprechenden Teil aus boost abgucken
    4.) Tobi_logoffs Code benutzen



  • Benutz lieber den Code von hier. Boost willst du dir nicht antun und der neue Standard braucht eh noch Jahre.



  • randnotiz schrieb:

    Benutz lieber den Code von hier. Boost willst du dir nicht antun und der neue Standard braucht eh noch Jahre.

    "Boost willst du dir nicht antun" ist ungefähr so sinnvoll wie "das funktioniert nicht" als Fehlermeldung. Warum sollte er es sich nciht antun wollen? Boost ist in 5-10 Minuten instaliert und einsatzbereit, und man muss ja nicht gleich alle Bibliotheken daraus benutzen. Fürs static_assert würde ich zwar auch eher die Loki-Version benutzen, allerdings wenn man boost bereits installiert hat ist das auch durchaus benutzbar. Die oben gepostete Version würde ich vermutlich nicht nutzen, da sie nicht so besonders ausgereift ist.
    Hier die Loki-Version:

    namespace Loki
    {
      template<int> struct CompileTimeError;
      template<> struct CompileTimeError<true> {};
    }
    ////////////////////////////////////////////////////////////////////////////////
    // macro STATIC_CHECK
    // Invocation: STATIC_CHECK(expr, id)
    // where:
    // expr is a compile-time integral or pointer expression
    // id is a C++ identifier that does not need to be defined
    // If expr is zero, id will appear in a compile-time error message.
    ////////////////////////////////////////////////////////////////////////////////
    #define LOKI_STATIC_CHECK(expr, msg) \
     { Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
    


  • pumuckl schrieb:

    ...
    da sie nicht so besonders ausgereift ist.
    ...

    Könntest du mir das erklären? Ich seh zur Loki version nur den Unterschied bool und int, in der eigentlichen Metafunktion. 😕



  • Tobi_logoff schrieb:

    Könntest du mir das erklären? Ich seh zur Loki version nur den Unterschied bool und int, in der eigentlichen Metafunktion. 😕

    Zum einen muss man in deinem Fall den Ausdruck zwischen dem struct-Namen und dem ::check() vergraben, da hätte zumindest noch ein Makro geholfen.
    Zum zweiten hat das Loki-Beispiel den Vorteil, dass man eine Aussagekräftige Fehlermeldung dazupacken kann:

    int main()
    {
      S_StaticAssert<(1 < 2)>::check(); //kompiliert;
      S_StaticAssert<(1 > 2)>::check(); //kompiliert nicht; //line 30
    
      LOKI_STATIC_CHECK(1 < 2, argument_must_be_less_than_2);
      LOKI_STATIC_CHECK(1 > 2, argument_must_be_greater_than_2);
    }
    
    In function 'int main()':
    Line 30: error: 'check' is not a member of 'S_StaticAssert<false>'
    
    In function 'int main()':
    Line 33: error: aggregate 'Loki::CompileTimeError<0> [b]ERROR_argument_must_be_greater_than_2[/b]' has incomplete type and cannot be defined
    

    Ich sag ja nicht dass es völliger Blödsinn ist, der Ansatz ist der richtige. Es fehlen bloß ein paar Kleinigkeiten, und da es die schon fertig zu holen gibt, braucht man das Rad nicht neu erfinden.



  • Boost ist eklig fett.



  • Vielen Dank. Ich habe mich für die Lösung von pumuckl entschieden (es gab viele Google treffer 🙂 ). Insgesamt ist mein Problem, dass ich nur nach std Programmieren darf und alles was dort nicht enthalten ist, bringt mir ärger.

    Leider ist mir noch einzweiter Fall eingefallen, den ich gerne mit Comilerfehlern abdecken möchte. Aber hier habe ich die Vermutung, dass man es nicht lösen kann:

    template <int Groesse>
    class Parkhaus
    {
        public:
            Parkplatz()
            {
            }
    
        protected:
            Parkplatz<Groesse> Parkeinheiten;
    
    }
    
    void main (int, char*)[]
    {
        Parkhaus<30> p1;
        Parkhaus<34> p2;
    
        //Geld wird investiert, Parkhäuser werden zusammen geführt
    
        p1 = p1 + p2; 
    }
    

    An dieser Stelle sehe ich noch ein gewaltiges Problem. Und zwar hat p1 nach der Vereinigung der Parkhäuser nun die Kapazität von 64 Parkplätzen. Die Addition der beiden Parkhäuser ist kein Problem. Mit Macros kann ich das Maximum auswerten und ein neues Objekt zurück geben. Aber kann ich dieses Objekt überhaupt zuweisen? Die Typen stimmen ja nicht mehr überein.

    Oder liege ich komplett neben der Spur? Wie immer bin ich über jeden Tipp dankbar.

    Viele Grüße
    MM

    Viele Grüße
    MM



  • Seltsames Beispiel. Und ein noch seltsameres main() 😉 😉

    Spricht irgendwas dagegen, die Anzahl der Parkeinheiten einfach als Parameter an den Ctor von Parkhaus zu übergeben?

    Stefan.



  • Ich denke mal, dass in diesem Fall die einfache Addition der Größen das Problem ist. So einfach liegt der Fall nämlich nicht. Effektiv entstehen ja nicht mehr Parkplätze. Also müßte im gleichen Zug Parkhaus 2 seine Parkplätze einbüßen - worauf es dann zur Bauruine wird, oder was auch immer. Es könnte sich sogar selbst abreißen - besser wäre es jedoch, dies von Parkhaus 1 aus zu machen.



  • MrMilk schrieb:

    Leider ist mir noch einzweiter Fall eingefallen, den ich gerne mit Comilerfehlern abdecken möchte.

    Dieser Code ist ein einziger Compilerfehler. Mission accomplished.



  • pumuckl schrieb:

    Tobi_logoff schrieb:

    Könntest du mir das erklären? Ich seh zur Loki version nur den Unterschied bool und int, in der eigentlichen Metafunktion. 😕

    Zum einen muss man in deinem Fall den Ausdruck zwischen dem struct-Namen und dem ::check() vergraben, da hätte zumindest noch ein Makro geholfen.
    Zum zweiten hat das Loki-Beispiel den Vorteil, dass man eine Aussagekräftige Fehlermeldung dazupacken kann:

    int main()
    {
      S_StaticAssert<(1 < 2)>::check(); //kompiliert;
      S_StaticAssert<(1 > 2)>::check(); //kompiliert nicht; //line 30
      
      LOKI_STATIC_CHECK(1 < 2, argument_must_be_less_than_2);
      LOKI_STATIC_CHECK(1 > 2, argument_must_be_greater_than_2);
    }
    
    In function 'int main()':
    Line 30: error: 'check' is not a member of 'S_StaticAssert<false>'
    
    In function 'int main()':
    Line 33: error: aggregate 'Loki::CompileTimeError<0> [b]ERROR_argument_must_be_greater_than_2[/b]' has incomplete type and cannot be defined
    

    Ich sag ja nicht dass es völliger Blödsinn ist, der Ansatz ist der richtige. Es fehlen bloß ein paar Kleinigkeiten, und da es die schon fertig zu holen gibt, braucht man das Rad nicht neu erfinden.

    Danke... 👍
    hätte schon gedacht ich sitze einem Fehler auf, den ich noch nicht gesehen habe.



  • DStefan schrieb:

    Seltsames Beispiel. Und ein noch seltsameres main() 😉 😉

    Uhh ja, da hast du recht.

    Mir geht es nur darum, was passiert, wenn man etwas zuweisen möchte und der Templateparamter (heißt es so, bin mir da nicht sicher?) nicht der gleiche ist.

    Ist dieses grundsätzlich nicht möglich oder muss man dann etwas bestimmtes machen...

    Viele Grüße
    MM



  • ady schrieb:

    Boost ist eklig fett.

    Wo ist Boost bitteschön "fett"? Die Boost-Bibliotheken sind eine Sammlung von vielen einzelnen Bibliotheken, häufig verwendet man aber in einem Projekt davon nur eine Handvoll.


Anmelden zum Antworten