conexpr vs Vorlage für die Kompilierzeit mathematische Funktionen?

8

Ich bin ziemlich verwirrt mit dem neuen Keyword constexpr von C ++ 2011. Ich würde gerne wissen, wo constexpr und wo Templates Metaprogrammierung verwenden, wenn ich kompilieren-Zeitfunktionen (vor allem mathematische Funktionen). Zum Beispiel, wenn wir eine ganzzahlige pow-Funktion nehmen:

%Vor%

Sind die 2. und 3. Funktionen gleichwertig? Was ist die beste Lösung? Führt es zu demselben Ergebnis:

  • wenn x zur Kompilierzeit bekannt ist
  • wenn x zur Kompilierzeit nicht bekannt ist

Wann wird constexpr verwendet und wann wird die Metaprogrammierung der Vorlage verwendet?

EDIT 1: Code geändert, um Spezialisierung für Vorlagen zu enthalten

    
Vincent 02.09.2012, 04:26
quelle

2 Antworten

8

Ich sollte wahrscheinlich so spät keine Metaprogrammierungsfrage beantworten. Aber hier bin ich.

Erstens, consExpr ist nicht in Visual Studio 2012 implementiert. Wenn Sie für Windows entwickeln möchten, vergessen Sie es. Ich weiß, es ist scheiße, ich hasse Microsoft, weil ich es nicht einbeziehe.

Damit gibt es eine Menge Dinge, die Sie als konstant deklarieren können, aber sie sind nicht wirklich "konstant" in Bezug auf "Sie können zur Kompilierungszeit mit ihnen arbeiten". Zum Beispiel:

%Vor%

Du könntest denken, dass du das zur Kompilierzeit lesen könntest, oder? Nee. Aber Sie können, wenn Sie es zu einem Constexpr machen.

%Vor%

Constexprs sind wirklich gut für die Optimierung der "konstanten Ausbreitung". Was das bedeutet ist, wenn Sie eine Variable X haben, die zur Kompilierzeit basierend auf einer Bedingung deklariert wird (vielleicht Metaprogrammierung), dann ist der Compiler sicher, dass er ihn "sicher" verwenden kann, wenn er eine Optimierung durchführt, um z. B. zu entfernen Anweisungen wie a = (X * y); und ersetze sie mit a = 0; wenn X zu 0 ausgewertet wird (und andere Bedingungen erfüllt sind).

Offensichtlich ist das großartig, denn für viele mathematische Funktionen kann die konstante Propagation Ihnen eine einfache (zu verwendende) vorzeitige Optimierung geben.

Ihre hauptsächliche Verwendung, abgesehen von eher esoterischen Dingen (wie zum Beispiel die Möglichkeit, einen Kompilierzeit-Bytecode-Interpreter viel einfacher zu schreiben), besteht darin, "Funktionen" oder Klassen zu erstellen, die beide aufgerufen und verwendet werden können zur Kompilierzeit und zur Laufzeit.

Im Grunde füllen sie nur ein Loch in C ++ 03 und helfen beim Optimieren durch den Compiler.

Also, welches Ihrer 3 ist "am besten"?

2 kann zur Laufzeit aufgerufen werden, während die anderen nur zur Kompilierzeit dienen. Das ist ziemlich süß.

Da ist noch etwas mehr. Wikipedia gibt Ihnen eine sehr einfache Zusammenfassung von "constexpr ermöglicht dies", aber Template-Metaprogrammierung kann kompliziert sein. Contexpr macht Teile davon viel einfacher. Ich wünschte, ich hätte ein klares Beispiel für dich, außer zu sagen, aus einem Array zu lesen.

Ein gutes mathematisches Beispiel wäre vermutlich, wenn Sie eine benutzerdefinierte komplexe Zahlenklasse implementieren möchten. Es wäre eine Größenordnung komplexer, nur mit Template-Metaprogrammierung und ohne consExpr zu programmieren.

Wann sollten Sie also nicht constexpr verwenden? Ehrlich gesagt, Constexpr ist im Grunde "const außer MORE CONST." Sie können es im Allgemeinen überall verwenden, wo Sie const verwenden würden, mit ein paar Vorbehalten wie zum Beispiel, wenn eine Funktion während der Laufzeit nicht-const wirkt, wenn ihre Eingabe nicht const ist.

Ähm. OK, das ist alles für jetzt. Ich bin zu übermüdet, um mehr zu sagen. Ich hoffe, dass ich hilfreich war, fühlen Sie sich frei, mich zu senken, wenn ich nicht war, und ich werde das löschen.

    
std''OrgnlDave 02.09.2012, 05:37
quelle
1

1. und 3. sind falsch. Der Compiler versucht, tpow<N-1> zu instanziieren, bevor er (N>0) ? auswertet, und Sie erhalten eine unendliche Vorlagenrekursion. Sie benötigen Spezialisierung für N==1 (oder ==0 ), damit es funktioniert. 2. wird für x zur Kompilierzeit und Laufzeit funktionieren.

Nach Ihrer Spezialisierung für ==0 edit hinzugefügt. Jetzt funktionieren alle Funktionen für die Kompilierzeit oder die Laufzeit x . 1. wird immer nicht constexpr Wert zurückgeben. 2. und 3. werden conetexpr zurückgeben, wenn x und N constexpr sind. 2. funktioniert sogar, wenn N nicht consxpr ist, andere brauchen constexpr N (also, 2. und 3. sind nicht gleichwertig).

Der consExpr wird in zwei Fällen verwendet. Wenn Sie int N=10; schreiben, ist der Wert von N zur Kompilierzeit bekannt, aber er ist nicht conexpr und kann nicht als Beispiel für ein Argument verwendet werden. Das Schlüsselwort constexpr teilt dem Compiler ausdrücklich mit, dass N als Kompilierzeitwert sicher zu verwenden ist. Die zweite Verwendung ist als Constexpr-Funktionen. Sie verwenden eine Teilmenge von C ++ zur konditionellen Erzeugung von conexpr-Werten und können die äquivalenten Template-Funktionen dramatisch vereinfachen. Ein Nachteil der conexpr-Funktionen ist, dass Sie keine garantierte Kompilierzeitauswertung haben - der Compiler kann die Auswertung in der Laufzeit auswählen. Mit der templateten Implementierung ist die Kompilierzeitauswertung garantiert.

    
Leonid Volnitsky 02.09.2012 05:02
quelle