Kann mir jemand erklären, warum die erste Meta-Programmiermethode für Vorlagen in eine Endlosschleife geht, die zweite jedoch korrekt ausgeführt wird.
#include <iostream>
using namespace std;
template<int N, int M>
struct commondivs {
static const int val = (N<M) ? commondivs<N,(M-N)>::val : commondivs<(N-M),M>::val;
};
template<int N>
struct commondivs<N,N> {
static const int val = N;
};
int commondiv(int N, int M){
if(N==M){
return N;
}
return (N<M)?commondiv(N,(M-N)):commondiv((N-M),M);
}
int main() {
cout << commondivs<9,6>::val << endl;
cout << commondiv(9,6) << endl;
return 0;
}
constexpr
ist keine Option.constexpr
keine Option ist. (Es wurde in C ++ 11 eingeführt). Dadurch werden vorhandene Antworten ungültig. Exxul, bitte klären Sie, auf welche C ++ - Version Sie beschränkt sind.Antworten:
Diese Zeile bewirkt die Instanziierung von beiden
commondivs<N,(M-N)>::val
undcommondivs<(N-M),M>::val
, selbst wenn die Bedingung zur Kompilierungszeit bekannt ist und einer der Zweige niemals genommen wird.Ersetzen Sie
? :
durchstd::conditional_t
, was diese Einschränkung nicht hat:quelle
Das Problem ist , alle Operanden von Bedingungsoperator ausgewertet, so dass beide werden
commondivs<N,(M-N)>
undcommondivs<(N-M),M>
erhalten instanziiert und derenval
get ausgewertet und dann führt zu rekursive Template - Instantiierung.Sie können constexpr if anwenden und in eine
constexpr
static
Member-Funktion einfügen .LEBEN
quelle
::val
muss in beiden Zweigen sicher generiert werden, dies ist jedoch immer noch eine Instanziierung (einer Vorlage mit einem statischen const-Element). Die Auswertung zur Laufzeit findet nicht statt ... nun, es kann offensichtlich nicht, da es nie kompiliert wird ...Der ternäre Operator ist nicht wie folgt
if constexpr
: Wenn ein Compiler ihn sieht, muss er Code für beide Zweige generieren. Mit anderen Worten, um eine Vorlage zu instanziieren, instanziiertcommondivs<M, N>
ein Compiler sowohl Vorlagencommondivs<N, M - N>
als auchcommondivs<N - M, M>
.Im Gegensatz dazu
commondiv(N, M - N)
undcommondiv(N - M, M)
werden in zwei Funktionsaufrufe übersetzt. Welche genommen wird, wird entschieden, wann die Funktion tatsächlich aufgerufen wird.Zusatz.
HolyBlackCat gab eine Lösung mit
std::conditional_t
. Hier ist noch einer:quelle
Sie erhalten eine unendliche Rekursion, weil:
ist überhaupt keine Metatemplate-Programmierung, weil
?:
, wie @Eng sagt, dies nicht der Fall istconstexpr
.Sie möchten sich die Antwort von @ HolyBlackCat ansehen.
quelle
?:
ist nichtconstexpr
.