Faking Static Wenn in C ++

8

Ich teste Kombinationen von verschiedenen Optimierungen und für diese brauche ich eine statische-if ​​wie in Ссылка , um bestimmte Optimierungen zu aktivieren und zu deaktivieren. if (const-expr) funktioniert nicht immer, da bei einigen Optimierungen das Datenlayout geändert wird und dies nicht im Funktionsumfang erfolgen kann.

Grundsätzlich was ich will ist das:

%Vor%

(Ja, der kleinere Speicherbedarf beim Entfernen von b aus dem Datenlayout ist in meinem Fall relevant.)

Momentan fälsche ich es mit einem sehr schlechten Hack. Ich suche nach einem besseren Weg, dies zu tun.

Datei a.h

%Vor%

Datei b.h (diese Datei wird automatisch aus einem Python-Skript erstellt)

%Vor%

Datei c.h

%Vor%

Weiß jemand einen besseren Weg, dies zu tun? Theoretisch kann es mit Template-Metaprogrammierung gemacht werden und ich habe es zuerst benutzt. Zumindest war die Art und Weise, wie ich es benutzte, eine Nervensäge und führte zu völlig unlesbarem und aufgeblähtem Code. Die Verwendung des obigen Hacks führte zu einer erheblichen Produktivitätssteigerung.

EDIT: Ich habe mehrere Optimierungsflags und diese interagieren.

    
B.S. 21.07.2012, 13:24
quelle

3 Antworten

6

Es gibt keinen Grund, warum der Code mit Templates viel komplizierter werden sollte:

%Vor%

Es ist keine Metaprogrammierung erforderlich, trennen Sie einfach die Teile, die davon abhängen, ob die Optimierung in einen neuen Typ aktiviert ist, und spezialisieren Sie sie.

Da der neue Typ als Basisklasse verwendet wird, wenn er leer ist (d. h. es gibt kein FooOptimized::b -Member), nimmt er keinen Platz ein, also sizeof(Algo<false>::Foo) == sizeof(int) .

(Fühlen Sie sich frei, den Rest dieser Antwort zu ignorieren, es geht nicht direkt auf die Frage ein, sondern schlägt einen anderen Ansatz vor, der unterschiedliche Kompromisse hat. Ob es "besser" ist oder nicht, hängt ganz von den Details ab der echte Code, die in dem in der Frage gegebenen trivialen Beispiel nicht gezeigt werden.)

Als zusammenhängendes, aber separates Problem hängen die Teile von Algo und Algo::Foo , die nicht davon abhängen, ob die Optimierung aktiviert ist, immer noch vom Vorlagenparameter ab, also nur von Ihnen Schreiben Sie diese Code-Bits einmal, generiert der Compiler zwei Objektcode-Sätze. Abhängig davon, wie viel Arbeit in diesem Code steckt und wie er verwendet wird, könnte es sich als vorteilhaft erweisen, dies in Nicht-Template-Code zu ändern, d. H. Statischen Polymorphismus durch dynamischen Polymorphismus zu ersetzen. Beispielsweise könnten Sie das Argument enable_optimization anstelle eines Vorlagenarguments ein Laufzeitkonstruktorargument verwenden:

%Vor%

Sie müssten ein Profil erstellen und testen, um festzustellen, ob die virtuelle Funktion mehr Aufwand als die Duplizierung von Code in Algo und Algo::Foo hat, die nicht vom Vorlagenparameter abhängig ist.

    
Jonathan Wakely 21.07.2012 14:12
quelle
1

Hinweis: So wie es aussieht, funktioniert dieser Ansatz nicht, da es anscheinend keine Möglichkeit gibt, ein Mitglied in einer Klasse zu haben, ohne Platz für dieses Mitglied zu reservieren. Wenn Sie eine Idee haben, wie es funktioniert, können Sie es bearbeiten.

Sie könnten ein Idiom wie folgt verwenden:

%Vor%

Wenn die Optimierung deaktiviert ist, erhalten Sie ein normales int -Member. Wenn die Optimierung aktiviert ist, ist der Typ von b eine Struktur ohne Elemente, die keinen Platz beanspruchen.

Wie Ihre Methode bar verwendet, sieht wie eine Laufzeit if aus, um zu entscheiden, ob b im Gegensatz zu einem Mechanismus zur Kompilierungszeit wie Template-Spezialisierung auf alle Operationen in% co_de zugreifen soll % muss auch von der Dummy-Struktur verfügbar sein. Selbst wenn die relevanten Abschnitte niemals ausgeführt werden und der Compiler sie höchstwahrscheinlich optimiert, kommen die Korrektheitsprüfungen zuerst. Also muss die Zeile b auch für den Ersetzungstyp kompiliert werden. Das ist der Grund für die Dummy-Zuweisung und die Dummy-Cast-Operationen. Obwohl beides für Ihren Code ausreichen würde, habe ich beide hinzugefügt, falls sie sich an einem anderen Punkt als nützlich erweisen, und um Ihnen eine Idee zu geben, wie Sie mehr hinzufügen können, sollten Sie sie jemals benötigen.

    
MvG 21.07.2012 16:16
quelle
0

Die statische Lösung von Jonathan Wakely (nicht die dynamische) ist der richtige Weg.

Die Idee ist einfach:

  1. Isolieren Sie die "spezifischen" Daten in eine eigene Klasse (nach Vorlage und entsprechend spezialisiert)
  2. Alle Zugriffe auf diese Daten werden komplett an die spezialisierte Klasse übergeben (die Schnittstelle muss einheitlich sein)

Um keinen Platz-Overhead zu verursachen, verwenden Sie die EBO (Empty Base Optimization) zu Ihrem Vorteil, indem Sie entweder die Spezialisierung dieser speziellen Klasse übernehmen.

Hinweis: Ein Attribut muss mindestens 1 Byte Speicherplatz belegen, eine Basisklasse ist unter bestimmten Bedingungen nicht verfügbar (z. B. leer).

In Ihrem Fall:

  • b sind die spezifischen Daten
  • es gibt eine einzige Operation, die es beinhaltet (was darin besteht, seinen Wert zu setzen)

So können wir leicht eine Klasse konstruieren:

%Vor%

Und dann können wir es in Foo einfügen, wobei wir EBO zu unserem Vorteil verwenden:

%Vor%

Hinweis: Verwenden Sie this im Vorlagencode, um auf Mitglieder von Basisklassen zuzugreifen, oder gute Compiler lehnen Ihren Code ab.

    
Matthieu M. 21.07.2012 16:13
quelle