Производительность хвостовой рекурсии при метапрограмме шаблона

Общей оптимизацией компилятора является преобразование хвостовых рекурсивных функций в циклы, ускорение времени выполнения и сокращение потребления памяти (стека):

int go_to_zero( int n )
{
    if( n == 0 )
        return 0;
    else
        return go_to_zero( n - 1 );
}

Мой вопрос прост: Есть ли какое-либо преимущество в производительности (т.е. сокращение времени компиляции), выполняющее хвостовые рекурсивные алгоритмы метапрограммирования шаблонов?

Вот пример:

template<typename... Ts>
struct list {};


template<typename LIST>
struct reverse;


template<typename HEAD , typename... TAIL>
struct reverse<list<HEAD,TAIL...>>
{
    using result = concat<typename reverse<list<TAIL...>>::result,list<HEAD>>;
};

template<>
struct reverse<list<>>
{
    using result = list<>;
};

против

template<typename INPUT , typename OUTPUT>
struct reverse_impl;


template<typename HEAD , typename... TAIL , tyename... Ts>
struct reverse_impl<list<HEAD,TAIL...>,list<Ts...>>
{
    using result = typename reverse_impl<list<TAIL...>,list<Ts...,HEAD>>::result;
};

template<typename... Ts>
struct reverse_impl<list<>,list<Ts...>>
{
    using result = list<Ts...>;
};

template<typename LIST>
using reverse = typename reverse_impl<LIST,list<>>::result;

Ответ 1

В С++ Template Metaprogramming Приложение C "Производительность времени компиляции" Абрахам и Гуртовой выслушали, как время компиляции воспоминаний о моментах создания шаблона. Книга была написана в 2005 году, и я думаю, что мемуаризация сегодня лучше реализована (я не измерял). Таким образом, вопрос ответа заключается в том, какая реализация может принести больше пользы от воспоминаний. Я немного изменил код Версия 1 и Версия 2. Теперь он выдает ошибку при создании reverse_impl, поэтому мы можем просто подсчитать ошибки. Я отменяю 2 списка list<int, short, char> и list<short, char>. Версия 1 испускает 4 ошибки, а версия 2 испускает 7 ошибок. В этом конкретном случае версия 1 извлекает выгоду из memoization с этими двумя списками (list2 - это хвост списка1), а версия 2 - нет. Поэтому я ожидаю, что версия 1 будет быстрее.

Итак, было бы лучше реализовать алгоритмы с точки зрения других алгоритмов, которые, как известно, извлекают выгоду из memoization, и я думаю, что большинство из них использует рекурсию головы.

Ответ 2

Все плюсы и минусы регулярной или хвостовой рекурсии применяются также к метапрограммированию. Разница в этом случае заключается в том, что вместо выполнения скомпилированной программы на целевой машине программа выполняется в песочнице компилятора и компилируется на целевой язык, а не на машинный язык. Этот процесс концептуально не сильно отличается от компиляции Java-программы в байт-код.

Компиляторы С++ имеют довольно ограниченную допустимую глубину вложенности шаблонов (~ сотни), и если алгоритм растет экспоненциально, это может быть блокирующим использование регулярной рекурсии; хвостовая рекурсия может помочь здесь.