Магия Шаблонов Или Расчет Факториала На Этапе Компиляции

Добрый день, Хабралуди! Гуру C++, а также люди, разбирающиеся в метапрограммировании шаблонов, могут смело пропустить эту тему; они не найдут здесь для себя ничего нового.

Однако, если после прочтения заголовка в вашей голове еще не возникло решение данной проблемы (и даже если оно возникло, но не с помощью шаблонов), то милости просим под кат. Собственно решение проблемы:

  
  
  
  
  
  
   

#include <iostream> template<int n> class Factorial { public: static const int f = Factorial<n - 1>::f * n; }; template<> class Factorial<0> { public: static const int f = 1; }; int main() { std::cout << Factorial<5>::f << std::endl; // 120 }

Давайте разберемся, что к чему.

Во-первых, некоторые могут спросить — а почему значение вычисляется на этапе компиляции? Ответ — основа шаблонов в C++.

Специализированный код генерируется на этапе компиляции в зависимости от того, каким типом фактически был параметризован шаблон.

Дело в том, что если вы используете, например, шаблон функции, возвращающий как минимум два значения:

template<class T> const T& min(const T& a, const T& b) { return (a < b) ? a : b; }

Затем, если вы используете его в программе, например:

min(2, 3)

Тогда будет сгенерирована только специализация для типа.

интервал .

А если написать что-то вроде:

min(2.0, 3.0)

Затем будет создана специализация для двойной .

Теперь, возвращаясь к нашему факториалу, мы можем понять, что для генерации факториала<5> шаблон, Факториал<4> шаблон должен быть сгенерирован и так далее до нуля, где в факториале записан только один<0> ::f (из-за явной специализации шаблон<> ).

Этот последний шаг останавливает «рекурсивную» генерацию шаблонов, после чего вычисляется само значение факториала.

Почему на этапе компиляции? Потому что константа static const int f является константой времени компиляции.

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

В книге Брюса Оккеля Философия C++.

Практическое программирование .

Дано следующее решение этой задачи (по сути ничем не отличающееся от вышеизложенного):

template<int n> struct { enum {val = Factorial<n - 1> * n}; }; template<> struct Factorial<0>{ enum {val = 1}; };

В общем, такой расчет факториала — это частный случай шаблонного метапрограммирования.

Например, возведение целого числа p в степень q можно записать в цикле:

int power = 1; while (q--) power *= p;

Но это также возможно с использованием метапрограммирования шаблонов:

template<int p, int q> class Power { public: static const int value = p * Power<p, q - 1>::value; }; template<int p> class Power<p, 0> { public: static const int value = 1; }

Подробнее об этом можно прочитать, например, у Ккеля, в книге Философия C++.

Практическое программирование , или в книге Александреску Современный дизайн на C++ .

Спасибо за внимание! Теги: #C++ #факториал #шаблоны #шаблон #магия шаблонов #C++

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.