Beim Durchsuchen der Interviewprotokolle nach der Position des Entwicklers stellte ich das folgende Problem fest: "Bieten Sie einen Code an, der Zahlen in absteigender Reihenfolge von n auf 0 druckt, ohne (versteckte oder explizite) Vergleichsoperatoren zu verwenden (die Implementierung der Druckfunktion zählt nicht)." Trotz der Tatsache, dass diese Aufgabe nichts mit mir zu tun hatte, beschäftigte sie mich und ich beschloss, über Lösungsmöglichkeiten nachzudenken (obwohl ich immer noch nicht weiß, wer und wann welche Aufgabe diese Methode der Codeoptimierung erfordern würde).
Das erste, was mir in den Sinn kam, war, Muster zu verwenden. Wie so
template<int n> void print() { printf("%d\n", n); print<n - 1>(); } template<> void print<0>() { printf("0\n"); } int main(int argc, char* argv[]) { print<N>(); return 0; }
Das Problem ist, dass die Programmierung eine technische Disziplin ist, keine okkulte, und wenn "etwas" im System passieren sollte, sollte "es" beschrieben und Ressourcen dafür zugewiesen werden, und in diesem Fall, da die Entwicklung von Vorlagen stattfindet In der Kompilierungsphase gibt es Einschränkungen für die Verschachtelung solcher Konstruktionen (und es ist gut und korrekt, und Gott sei Dank, dass dies der Fall ist), und der Compiler hat zu Recht den "schwerwiegenden Fehler C1202: Rekursiver Typ- oder Funktionsabhängigkeitskontext zu komplex" mit einer Größe N größer ausgegeben 2000.
Das nächste, was mir in den Sinn kam, war die Verwendung der klassischen Methode mit Zeigern auf Funktionen.
typedef void(*PrintFunc)(int); void printZero(int); void printNumber(int n); PrintFunc g_functors[] = {printZero, printNumber}; void printZero(int) { printf("0\n"); } void printNumber(int n) { printf("%d\n", n--); g_functors[!!n](n); } int main(int argc, char* argv[]) { printNumber(N); return 0; }
Aber selbst dann machten sich die uns durch das Naturgesetz auferlegten Einschränkungen bemerkbar, und da die Verschachtelung von Funktionsaufrufen durch die Größe des Stapels begrenzt ist, wurde ein legitimer "Stapelüberlauf" mit einem Wert von N> 4630 erhalten.
An diesem Ort ergriffen mich Enttäuschung und Wut völlig und ich erkannte, dass man für eine vollständige Lösung dieses Problems nichts meiden sollte, einschließlich der schmutzigsten Tricks. Das Problem ist, dass wir für bestimmte Werte von N die Kontrolle auf die erforderlichen Abschnitte des Codes übertragen müssen. Und dies ist kein Problem, wenn wir bedingte Aussagen zur Verfügung haben, aber wenn sie nicht da sind, müssen wir auf Hexerei zurückgreifen. In der Antike konnte dies mit der goto-Methode gelöst werden, aber seitdem haben Hexenjäger und andere Drachenkämpfer ihre Funktionalität stark eingeschränkt (und das ist auch gut und richtig) und wir möchten so etwas schreiben
g_functors[0] = [](int){print("0\n"); goto end; } g_functors[1] = [](int n){print("%d\n", n); goto begin; } begin: g_functors[!!n](n--); end:
aber wir können nicht.
Obwohl es mir verboten war, mich auf schwarze Magie einzulassen, entschied ich mich in diesem Fall, eine Ausnahme zu machen, indem ich dem vorherigen Beispiel ein wenig Magie hinzufügte.
void printZero(int); void printNumber(int n); PrintFunc g_functors[] = {printZero, printNumber}; void printZero(int) { printf("0\n"); throw 0; } void printNumber(int n) { printf("%d\n", n); } int main(int argc, char* argv[]) { int n = N; try{ begin: g_functors[!!n](n--); goto begin; } catch (...){} return 0; }
Und dies löste das Problem vollständig (für jedes N).
PS: Ich würde mich freuen, von anderen Methoden zur Lösung dieses Problems zu hören