Нет, невозможно сообщить компилятору, что требуется хвостовая рекурсия. Некоторые компиляторы (мне неизвестные) могут поддерживать аннотации, специфичные для реализации, но для этого требуется, чтобы пользователь использовал этот конкретный компилятор. Некоторые другие компиляторы в некоторых режимах намеренно никогда не поддерживают хвостовые вызовы, потому что они могут обеспечить лучший опыт отладки, не поддерживая хвостовые вызовы. Пользователь может использовать такой компилятор.
Допустимая глубина рекурсии сильно зависит от программы, функции и реализации, и для нее нельзя указать разумные числа. Учитывая конкретную платформу, вы, вероятно, можете определить размер стека по умолчанию, исследовать размер кадра для одного конкретного компилятора на этой платформе и выполнить простое деление, чтобы получить приблизительную оценку того, сколько вложенных вызовов вы можете иметь.
Я рекомендую переписать его таким образом, чтобы читатель понял, что происходит, но не полагался на компилятор, оптимизирующий хвостовые вызовы. Несмотря на ненависть, оператор goto
может быть очень полезен для этого.
Возьмем простую функцию подсчета битов с хвостовой рекурсией:
int bitcount(unsigned int n, int acc = 0) {
if (n == 0)
return acc;
return bitcount(n >> 1, acc + (n & 1));
}
Его можно тривиально переписать как
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;
}
Конечно, это простая версия, которая тривиально переписана, чтобы полностью избежать рекурсии, и, вероятно, ее даже не следует реализовывать вручную, но конкретное преобразование, которое я здесь использовал, можно применить к любому функция, где хвостовая рекурсия возможна и где вам нужна хвостовая рекурсия. Комментарий должен гарантировать, что читатель все еще может легко определить, что происходит.
person
Community
schedule
26.05.2015