Nie, nie ma sposobu, aby powiedzieć kompilatorowi, że rekurencja ogona jest wymagana. Niektóre kompilatory (których nie znam) mogą obsługiwać adnotacje związane z implementacją, ale wymaga to użycia tego konkretnego kompilatora. Niektóre inne kompilatory, w niektórych trybach, celowo nigdy nie obsługują wywołań ogonkowych, ponieważ mogą zapewnić lepsze wrażenia debugowania poprzez nieobsługiwanie wywołań ogonowych. Użytkownik może używać takiego kompilatora.
Dozwolona głębokość rekursji zależy w dużym stopniu od programu, funkcji i implementacji i nie można podać dla niej żadnych sensownych liczb. Biorąc pod uwagę konkretną platformę, możesz prawdopodobnie określić domyślny rozmiar stosu, zbadać rozmiar ramki dla konkretnego kompilatora na tej platformie i wykonać prosty podział, aby uzyskać przybliżoną liczbę połączeń zagnieżdżonych, jakie możesz mieć.
Polecam przepisanie go w sposób, który wyjaśnia czytelnikowi, co się dzieje, ale nie polega na kompilatorze optymalizującym ogonki. Chociaż znienawidzone, instrukcja goto
może być bardzo przydatna.
Weźmy prosty ogon rekurencyjnej funkcji bit licznikami:
int bitcount(unsigned int n, int acc = 0) {
if (n == 0)
return acc;
return bitcount(n >> 1, acc + (n & 1));
}
Można trywialnie przepisany jako
int bitcount(unsigned int n, int acc = 0) {
tail_recurse:
if (n == 0)
return acc;
// tail return bitcount(n >> 1, acc + (n & 1));
acc += n & 1;
n = n >> 1;
goto tail_recurse;
}
Oczywiście jest to proste wersję, która jest trywialnie przepisany w celu uniknięcia rekursji całkowicie , i prawdopodobnie nie powinien nawet zostać zaimplementowany ręcznie, ale konkretna transformacja, której użyłem tutaj, to taka, którą można zastosować do dowolnej funkcji, gdzie rekurencja ogona jest możliwa i gdzie potrzebna jest rekurencja ogona. Komentarz powinien upewnić się, że czytelnik nadal może łatwo zauważyć, co się dzieje.
Ile połączeń typu tail oczekujesz z grubsza?Jakie kompilatory kierujesz na siebie? – Guvante
Jeśli jest to naprawdę rekurencyjne i musisz wiedzieć na pewno, że kompilator zoptymalizuje rekursję, powinno być proste, aby samemu zakodować go jako pętlę. – jxh
Zobacz [tę odpowiedź] (http://stackoverflow.com/a/30090390/315052), aby znaleźć inne powody, dla których funkcja rekursywna ogona może nie zostać zoptymalizowana. – jxh