Blog Konstante Ausdrücke in C++11 (ehemals C++0x)

DMA

Komplett-PC-Käufer(in)
Was sind konstante Ausdrücke?

Wie bei der Template Metaprogrammierung, sollen bei konstanten Ausdrücken Werte zur Compile-Zeit berechnet werden.
Der Sinn des Ganzen ist es, feststehende Werte (Konstanten) nicht zur Berechnung auf die Laufzeit zu schieben, denn ihr Wert ändert sich nie.
Ein einfaches Beispiel wäre power(16, 2).
Dieser Funktionsaufruf wird immer 256 liefern, egal wann er mit diesen Parametern im Programm aufgerufen wird.
Bis vorkurzem ging das in C++ nur mit - für ungeübte Programmierer - unübersichtlichen Templates.
Mit C++11 wird nun das Keyword constexpr eingeführt - analog zu dem älteren const für feste Werte.

Die Syntax bei constexpr ist die übliche von C++, was das Ganze besonders einfacher zu lesen macht.
Konstante Ausdrucks-Metaprogrammierung (constexpr meta-programming) wird in C++11 deswegen wahrscheinlich das Mittel der Wahl für Metaprogrammierung sein.

Potenzierung per rekursiven Verfahren
Vor C++11 musste dies per TMP implementiert werden, dies möchte ich hier nicht näher erläutern, aber zum Vergleich trotzdem einmal den Quelltext zeigen,
damit nachher ein besserer Vergleich und Eindruck von und zwischen CMP und TMP entsteht.
PHP:
template<int tmp_Basis, unsigned int tmp_Exponent>
struct tmp_Power
{
    enum
    {
        tmp_result = tmp_Basis * tmp_Power<tmp_Basis, tmp_Exponent-1>::tmp_result
    };
};

template<int tmp_Basis>
struct tmp_Power<tmp_Basis, 0>
{
    enum
    {
        tmp_result = 1
    };
};
Ein Aufruf für die Potenzierung von 16^2 sähe wie folgt aus: tmp_Power<16, 2>::tmp_result.
Dies entspricht nicht der gewohnten C++ Syntax und wird bei größeren Berechnungen auch mal schnell unübersichtlich, wenn die Dokumentation nicht stimmt.
Ein weiteres Problem ist, dass der Datentyp double (sowie float) in der TMP nicht zur Verfügung steht.
Ein Aufruf wie tmp_Power<8.5, 2> ginge somit nicht.

Das selbe Verfahren mit der CMP sieht um Längen verständlicher aus und könnte (bis auf das Keyword constexpr) auch C++03 Code sein:
PHP:
constexpr double power(double basis, unsigned int exponent)
{
  return !exponent ? 1 : basis * power(basis, exponent-1);
}
Diese Funktion wirkt wie jede andere in C++ auch, ist aber ein konstanter Ausdruck. Konstante Werte werden also nicht erst zur Laufzeit berechnet.
Im Unterschied zur TMP kann man CMP aber auch mit Laufzeitwerten füttern, dann wird allerdings erst die Berechnung des Wertes zur Laufzeit durchgeführt.

Der folgende Aufruf gibt 72.25 aus:
PHP:
printf("power(8.5, 2) = %f\n\n", power(8.5, 2));
Zur Laufzeit wird nurnoch printf(..., 72.25); übergeben ansteller längeren rekursiven Berechnung.
Hier einmal der Vergleich:
PHP:
static_assert(power(8.5, 2), "...power"); // Compile-Zeit
double a = 8.5;
power(a, 2); // Laufzeit
Auswirkungen auf die Compile-Zeit
Wer TMP nutzt weiß, dass viele Rekursionen (5000+) erhebliche Zeit in Anspruch nehmen.
Doch CMP mit großer Tiefe (z.B. das Generieren von Primzahlen) benötigt nur ein Bruchteil der Zeit.
CMP wurde extra für die Metaprogrammierung entworfen, während TMP eher "entdeckt" wurde.
Daher sind viele Optimierungsprozesse für CMP von Anfang an vorhanden, während bei der TMP z.B. oft Analysen mehrfach durchgeführt werden, da der eine Aufruf vom Anderen nichts weiß.

Alles in Allem wird die konstante Ausdrucks-Metaprogrammierung die Metaprogrammierung in C++ erheblich voran treiben, da auch weniger Metaprogrammierung versierte Programmierer diesen Mechanismus nutzen können.

Weitere Artikel über Programmierung auch auf http://trogramming.wordpress.com)
 
Zurück