1

Ich habe vor kurzem in die Vorlage Metaprogrammierung mit C++ bekommen und habe versucht, einige grundlegende Funktionen in ihre jeweilige rekursive Kompilierungszeit Vorlage Definition zu konvertieren.Wie behandelt C++ rekursive Klassendefinitionen?

Zum Beispiel:

template <typename T, T A, unsigned int N> 
class pow { enum : T { value = A * pow<T, A, N-1>::value } }; 
template <typename T, T A> class pow<T, A, 0> { enum : T { value = 1 } }; 

Die Syntax und die Macht der Vorlagen erstaunt mich. Aber eine Frage nervt mich: Wie behandelt C++ diese rekursiven Definitionen? (Resource-wise)

Oder genauer gesagt:

  • Wie funktioniert der Compiler die Instanz Erstellung der Template-Klassen behandeln die ENUM-Werte, die (wo/wie der Speicher zugeordnet)?

  • Bleiben alle generierten Klassen nach der Kompilierung im Speicher oder werden sie vom Compiler optimiert, wobei nur die oberste Klasse (Cleanup) beibehalten wird?

  • Gibt es eine maximale rekursive Tiefe, die RAM-unabhängig ist (Einschränkungen durch den Compiler selbst)?

Eine ausführliche Erklärung bezüglich der Standardkompilierung solcher Strukturen wäre sehr willkommen.

+3

_ "Gibt es eine maximale rekursive Tiefe, die ..." _: g ++ hat '-ftemplate-depth = n' finden Sie unter: https: //gcc.gnu .org/onlinedocs/gcc/C_002b_002b-Dialekt-Optionen.html # C_002b_002b-Dialekt-Optionen –

+0

Es ist dann 1024. Aber ist es eine Compiler-Constraint oder nur eine Konvention (seit 17 ist eine seltsame Wahl für frühere C++ - Standards)? –

+1

Ich kann mir nicht vorstellen, dass ein Compiler die instanziierten Typen ablegt, schließlich hat es keine Möglichkeit zu wissen, ob es irgendwann in der Zukunft wieder verwendet wird. Nur während der Link-Phase wird eine Art Culling durchgeführt. Und mit der Metaprogrammierung würde ich erwarten, dass die Keulung vollständig ist. – SoronelHaetir

Antwort

1

pow::value ist const Express in Kompilierzeit. Compiler berechnet pow<T, A, N>::value von A * pow<T, A, N - 1>::value. A ist auch const Wert in der Kompilierung und würde Compiler weiterhin pow<T, A, N - 1>::value

...

berechnen pow<T, A, N - n>::value

berechnen pow<T, A, N - n - 1>::value

...

Compiler berechnet wird util stoppen finde keine Notwendigkeit, pow<T, A, 1>::value zu berechnen, weil das Programm pow<T, A, 1>::value = 1

definiert hat

schreiben Wenn

int main() { 
    int value = pow<int, 1, -1>::value; 
} 

gcc

fatal error: template instantiation depth exceeds maximum of xxx 

alarmieren würde Dies, weil Compiler finden could't ein const Wert vor dem Maximum der rekursiven Iteration erreichen.

Nach Kompilierung, Compiler nur den Wert als immediate number behalten, während keine Zwischenwert bleiben.

int main() { 
    400546:  55      push %rbp 
    400547:  48 89 e5    mov %rsp,%rbp 
    ... 
    int a = pow<int, 2, 8>::value; 
    40055d:  c7 45 f0 00 01 00 00 movl $0x100,-0x10(%rbp) 
    ... 
} 

$0x100 ist das Ergebnis der pow<int, 2, 8>::value. Es gibt keine zusätzliche Adresse, die dieses Ergebnis enthält.

Das Maximum der rekursiven Tiefe wird durch einen speziellen Compiler bestimmt.Beispiel: gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609 Das Standardmaximum ist 900. Der Programmierer könnte diesen Wert auf setzen.

Der Wert -ftemplate-depth konnte jedoch maximal int32 (2147483647) nicht überschreiten.

In dieser Struktur ist die Tiefe der Rekursion möglicherweise auch durch type T begrenzt.

int main() { 
    int result = pow<int, 2, 200>::value; 
} 

gcc würde alarmieren

error: overflow in constant expression [-fpermissive]