typedef vs öffentliche Vererbung in C ++ Meta-Programmierung

9

Disclaimer: Die Frage ist völlig anders als Vererbung statt typedef und ich konnte bisher keine ähnliche Frage finden

Ich spiele gerne mit C ++ - Template-Metaprogrammierung (zu Hause meistens, manchmal stelle ich es bei der Arbeit leicht vor, aber ich möchte nicht, dass das Programm nur für jemanden lesbar wird, der sich nicht darum gekümmert hat) Ich wurde von den Compiler-Fehlern ziemlich verwirrt, wenn etwas schief geht.

Das Problem ist natürlich, dass die c ++ Template-Metaprogrammierung auf der Vorlage basiert, und daher müssen Sie sich immer dann, wenn Sie einen Compilerfehler in einer tief verschachtelten Template-Struktur bekommen, in einer 10-Zeilen Fehlermeldung stutzen. Ich habe es mir sogar zur Angewohnheit gemacht, die Nachricht in einem Texteditor zu kopieren und einzufügen und dann die Nachricht einzurücken, um eine Struktur zu bekommen, bis ich eine Vorstellung davon habe, was tatsächlich passiert, was zur Nachverfolgung des Fehlers beiträgt.

>

Soweit ich weiß, ist das Problem hauptsächlich auf den Compiler und wie es typedefs ausgeben (es gibt andere Probleme wie die Tiefe der Verschachtelung, aber es ist nicht wirklich der Compilerfehler). Coole Features wie Variadic Templates oder Type Deduction (Auto) sind für das kommende C ++ 0x angekündigt, aber ich hätte gerne bessere Fehlermeldungen zum Booten. Es kann sich als schmerzhaft herausstellen, Template-Metaprogrammierung zu verwenden, und ich frage mich, was das werden wird, wenn mehr Leute tatsächlich in sie hineingehen.

Ich habe einige der typedefs in meinem Code ersetzt und stattdessen die Vererbung verwendet.

%Vor%

Das sind nicht viel mehr Zeichen, die zu tippen sind, und das ist meiner Meinung nach nicht weniger lesbar. In der Tat könnte es sogar lesbarer sein, da es garantiert, dass der deklarierte neue Typ in der Nähe des linken Randes erscheint, anstatt auf einem unbestimmten Versatz nach rechts zu liegen.

Dies beinhaltet jedoch ein anderes Problem. Um sicherzugehen, dass ich nichts Dummes getan habe, schrieb ich oft meine Vorlagenfunktionen / Klassen wie folgt:

%Vor%

Auf diese Weise war ich sicher, dass es nur für ein geeignetes Objekt aufgerufen werden kann.

Insbesondere beim Überladen von Operatoren wie operator + benötigen Sie eine Möglichkeit, den Umfang Ihrer Operatoren einzuschränken oder das Risiko einzugehen, dass sie zum Beispiel für int-Operatoren aufgerufen wurde.

Wenn dies jedoch mit einem typdefinierten Typ funktioniert, ist dies nur ein Alias. Es funktioniert sicher nicht mit Vererbung ...

Für Funktionen kann man einfach das CRTP

verwenden %Vor%

Dies ermöglicht es, den "echten" Typ zu kennen, der verwendet wurde, um die Methode aufzurufen, bevor der Compiler die öffentliche Vererbung verwendet hat. Man sollte beachten, dass dies die Wahrscheinlichkeit verringert, dass diese bestimmte Funktion aufgerufen werden muss, da der Compiler eine Transformation durchführen muss, aber ich habe bis jetzt noch nie ein Problem bemerkt.

Eine andere Lösung für dieses Problem besteht darin, meinen Typen eine 'tag'-Eigenschaft hinzuzufügen, um sie voneinander zu unterscheiden, und dann auf zu zählen SFINAE .

%Vor%

Es erfordert jedoch etwas mehr Schreibarbeit, besonders wenn man die Funktion / Methode an verschiedenen Stellen deklariert und definiert (und wenn ich meine Schnittstelle nicht störte, ist sie ziemlich schnell durcheinander). Wenn es jedoch um Klassen geht, wird die Transformation von Typen komplizierter:

%Vor%

Ich neige dazu, mehr die 'statische Behauptung' zu verwenden, die 'enable_if', ich denke, dass es viel lesbarer ist, wenn ich nach einiger Zeit zurückkomme.

Nun, im Grunde habe ich mich noch nicht entschieden und ich experimentiere immer noch zwischen den verschiedenen hier gezeigten Techniken.

Verwenden Sie typedefs oder Vererbung? Wie schränken Sie den Umfang Ihrer Methoden / Funktionen ein oder kontrollieren Sie anderweitig die Art der Argumente, die ihnen (und für Klassen) zur Verfügung gestellt werden?

Und natürlich hätte ich gerne mehr persönliche Vorlieben, wenn möglich. Wenn es einen vernünftigen Grund gibt, eine bestimmte Technik zu verwenden, würde ich es lieber wissen!

BEARBEITEN:

Ich habe stackoverflow durchsucht und gerade dieses Perl von Boost.MPL gefunden, das ich komplett vergessen hatte:

BOOST_MPL_ASSERT_MSG

Die Idee ist, dass Sie dem Makro 3 Argumente geben:

  • Die zu überprüfende Bedingung
  • eine Nachricht (C ++ - Kennung), die zur Anzeige in der Fehlermeldung
  • verwendet werden soll
  • die Liste der beteiligten Typen (als Tupel)

Dies kann sowohl bei der Code-Selbstdokumentation als auch bei der Fehlerausgabe erheblich helfen.

    
Matthieu M. 04.10.2009, 11:52
quelle

1 Antwort

4

Sie versuchen, explizit zu überprüfen, ob als Vorlagenargumente übergebene Typen die erforderlichen Konzepte bereitstellen. Kurz vor der Konzeptfunktion, die aus C ++ 0X herausgeworfen wurde (und somit einer der Hauptschuldigen dafür ist, dass sie zu C ++ 1X wird), ist es sicherlich schwierig, eine korrekte Konzeptüberprüfung durchzuführen. Seit den 90er Jahren gab es mehrere Versuche, Konzept-Checking-Bibliotheken ohne Sprachunterstützung zu erstellen, aber im Grunde haben alle diese Ergebnisse gezeigt, dass Konzepte, um es richtig zu machen, eher ein Merkmal der Kernsprache werden müssen als eine Nur-Bibliothek-Funktion.

Ich finde Ihre Ideen nicht statt typedef abzuleiten und enable_if sehr ansprechend zu verwenden. Wie Sie selbst gesagt haben, verdunkelt es oft den tatsächlichen Code nur wegen besserer Compiler-Fehlermeldungen.

Ich finde die statische Behauptung viel besser. Es erfordert keine Änderung des tatsächlichen Codes, wir sind alle daran gewöhnt, Assertion-Checks in Algorithmen zu haben und haben gelernt, sie mental zu überspringen, wenn wir die tatsächlichen Algorithmen verstehen wollen, es könnte bessere Fehlermeldungen erzeugen, und es wird nach C übertragen ++ 1X besser, die ein static_assert (vollständig mit vom Klassen-Designer bereitgestellten Fehlermeldungen) in die Sprache eingebaut hat. (Ich vermute, dass BOOST_STATIC_ASSERT einfach die eingebaute static_assert verwendet, falls diese verfügbar ist.)

    
sbi 04.10.2009, 12:20
quelle

Tags und Links