Как работает рекурсия времени компиляции?

Я нашел код здесь печатать 1 до 1000 без петли или conditionals

может кто-нибудь объяснить, как работает рекурсия времени компиляции, не смог найти его в google

// compile time recursion
template<int N> void f1()
{ 
    f1<N-1>(); 
    cout << N << 'n'; 
}

template<> void f1<1>() 
{ 
    cout << 1 << 'n'; 
}


int main()
{
    f1<1000>();
}

спасибо!

5 ответов


он неоднократно создает f1<N> шаблон с уменьшающимися значениями для N (f1<N>() звонки f1<N-1> и так далее). Явная специализация для N==1 завершает рекурсию: как только N становится 1, компилятор выберет специализированную функцию, а не шаблонную.

f1<1000>() компилятор инстанцировать f1<N> 999 раз (не считая последнего вызова f1<1>). Именно по этой причине для компиляции кода может потребоваться некоторое время широко использует методы метапрограммирования шаблонов.

все это сильно зависит от навыков оптимизации компилятора-в идеале, он должен удалить рекурсию (которая служит только для взлома, чтобы эмулировать for цикл с использованием шаблонов) полностью.


он работает концептуально почти так же, как рекурсия во время выполнения. f1<1000> звонки f1<999> и затем печатает 1000. f1<999> звонки f1<998> а затем печатает 999 и т. д. Как только он достигает 1, специализация шаблона действует как базовый случай для отмены рекурсии.


достаточно просто, каждый экземпляр шаблона создает новую функцию с измененным параметром. Например, если вы определили: f1_1000 (), f1_999 () и так далее.

каждая функция вызывает функцию с 1 меньше в его имени. Поскольку существует другой шаблон, не рекурсивный, для определения f1_1 () у нас также есть стоп-кейс.


это не гарантируется как чистая рекурсия во время компиляции. Компилятор должен будет создать экземпляр function f1() для всех параметров значение от 2 до 1000 и они будут называть друг друга.

тогда компилятор может увидеть, что эти вызовы можно просто превратить в последовательность cout << ... заявления. Возможно, это устраняет вызовы, возможно, нет - это зависит от компилятора. С точки зрения C++ это цепочка вызовов функций, и компилятор может делать все, что угодно, если это не так изменить поведение.


вычисления факториала объяснил здесь.

Кстати, обратите внимание, что ваша функция не работает для отрицательных чисел.