~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ 6F78EE2381C6A6317D586830CD6E5A0C__1717008000 ✰
Заголовок документа оригинал.:
✰ Template metaprogramming - Wikipedia ✰
Заголовок документа перевод.:
✰ Template metaprogramming - Wikipedia ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Template_metaprogramming ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/6f/0c/6f78ee2381c6a6317d586830cd6e5a0c.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/6f/0c/6f78ee2381c6a6317d586830cd6e5a0c__translat.html ✰
Дата и время сохранения документа:
✰ 16.06.2024 10:33:12 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 29 May 2024, at 21:40 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Template metaprogramming - Wikipedia Jump to content

Template metaprogramming

Из Википедии, бесплатной энциклопедии

Метапрограммирование шаблонов ( TMP ) — это метод метапрограммирования , при котором шаблоны используются компилятором для создания временного исходного кода , который компилятор объединяет с остальным исходным кодом и затем компилирует. Вывод этих шаблонов может включать времени компиляции константы , структуры данных и полные функции . Использование шаблонов можно рассматривать как полиморфизм времени компиляции . Этот метод используется во многих языках, наиболее известным из которых является C++ , а также Curl , D , Nim и XL .

Метапрограммирование шаблонов было в некотором смысле открыто случайно. [1] [2]

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

Components of template metaprogramming [ edit ]

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

Метапрограммирование шаблонов является полным по Тьюрингу , что означает, что любое вычисление, выражаемое компьютерной программой, может быть вычислено в той или иной форме метапрограммой шаблона. [3]

Шаблоны отличаются от макросов . Макрос — это фрагмент кода, который выполняется во время компиляции и либо выполняет текстовые манипуляции с компилируемым кодом (например, C++ макросы ), либо манипулирует абстрактным синтаксическим деревом , создаваемым компилятором (например, макросы Rust или Lisp ). Текстовые макросы значительно более независимы от синтаксиса языка, которым манипулируют, поскольку они просто изменяют текст исходного кода в памяти непосредственно перед компиляцией.

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

Using template metaprogramming [ edit ]

Хотя синтаксис метапрограммирования шаблонов обычно сильно отличается от языка программирования, на котором оно используется, он имеет практическое применение. Некоторые распространенные причины использования шаблонов — реализация общего программирования (избегание разделов кода, которые похожи, за исключением некоторых незначительных изменений) или выполнение автоматической оптимизации времени компиляции, например выполнение чего-либо один раз во время компиляции, а не при каждом запуске программы. например, заставляя компилятор разворачивать циклы для устранения переходов и уменьшения количества циклов при каждом выполнении программы.

Генерация классов во время компиляции [ править ]

Что именно означает «программирование во время компиляции», можно проиллюстрировать на примере функции факториала, которую на нешаблоном C++ можно записать с использованием рекурсии следующим образом:

беззнаковый   факториал  (  беззнаковый   n  )   { 
	 return   n   ==   0   ?    1   :   n   *   факториал  (  n   -   1  );  
  } 

 // Примеры использования: 
 // факториал(0) даст 1; 
  // факториал(4) даст 24. 

Приведенный выше код будет выполняться во время выполнения для определения факториала литералов 0 и 4. Используя метапрограммирование шаблонов и специализацию шаблонов для обеспечения конечного условия рекурсии, факториалы, используемые в программе (игнорируя любые неиспользуемые факториалы), могут быть вычислены во время компиляции с помощью этого кода:

шаблон   <  беззнаковое   N  > 
 struct   Factorial   { 
	 static   constexpr   беззнаковое   значение   =   N   *   факториал  <  N   -   1  >::  value  ; 
  }; 

  шаблон   <> 
 struct   Factorial  <  0  >   { 
	 static   constexpr   беззнаковое   значение   =   1  ; 
  }; 

  // Примеры использования: 
 // Factorial<0>::value даст 1; 
  // Factorial<4>::value даст 24. 

Приведенный выше код вычисляет факториал литералов 0 и 4 во время компиляции и использует результаты, как если бы они были предварительно рассчитанными константами. Чтобы иметь возможность использовать шаблоны таким образом, компилятор должен знать значение своих параметров во время компиляции, что имеет естественное предварительное условие: факториал<X>::value может использоваться только в том случае, если X известен во время компиляции. Другими словами, X должен быть константным литералом или константным выражением.

В C++11 и C++20 и consteval , были введены constexpr позволяющие компилятору выполнять код. Используя constexpr и consteval, можно использовать обычное рекурсивное определение факториала с нешаблонным синтаксисом. [4]

Оптимизация кода во время компиляции [ править ]

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

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

шаблон   <  int   длина  > 
 Vector  <  длина  >&   Vector  <  длина  >::  оператор  +=  (  const   Vector  <  длина  >&   rhs  )  
 { 
     for   (  int   i   =   0  ;   i   <   length  ;   ++  i  ) 
         value  [  i  ]   +=   РЗС  .   значение  [  я  ]; 
      вернуть   *  это  ; 
  } 

Когда компилятор создает экземпляр шаблона функции, определенного выше, может быть создан следующий код: [ нужна цитата ]

шаблон   <> 
 Vector  <  2  >&   Vector  <  2  >::  оператор  +=  (  const   Vector  <  2  >&   rhs  )  
 { 
     value  [  0  ]   +=   rhs  .   значение  [  0  ]; 
      значение  [  1  ]   +=   правая шкала  .   значение  [  1  ]; 
      вернуть   *  это  ; 
  } 

Оптимизатор компилятора должен иметь возможность развернуть for цикл, потому что параметр шаблона length является константой во время компиляции.

Однако будьте осторожны и соблюдайте осторожность, так как это может привести к раздуванию кода, поскольку для каждого N (размера вектора), с которым вы создаете экземпляр, будет генерироваться отдельный развернутый код.

Статический полиморфизм [ править ]

Полиморфизм — это общепринятое стандартное средство программирования, в котором производные объекты могут использоваться как экземпляры их базового объекта, но при этом будут вызываться методы производных объектов, как в этом коде.

class   Base 
 { 
 public  : 
     virtual   void   метод  ()   {   std  ::  cout   <<   "Base"  ;    } 
     виртуальный   ~  Base  ()   {} 
 }; 

  класс   Derived   :   public   Base 
 { 
 public  : 
     virtual   void   метод  ()   {   std  ::  cout   <<   "Derived"  ;    } 
 }; 

  int   main  () 
 { 
     Base   *  pBase   =   new   Derived  ; 
      pBase  ->  метод  ();    //выходы «Производные» 
     delete   pBase  ; 
      вернуть   0  ; 
  } 

где все вызовы virtualметоды будут принадлежать наиболее производному классу. Это динамически полиморфное поведение (обычно) достигается путем создания виртуальных справочных таблиц для классов с виртуальными методами, таблиц, которые просматриваются во время выполнения для идентификации вызываемого метода. Таким образом, полиморфизм во время выполнения обязательно влечет за собой накладные расходы на выполнение (хотя в современных архитектурах накладные расходы невелики).

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

шаблон   <  класс   Derived  > 
 struct   base 
 { 
     void   интерфейс  () 
     { 
          // ... 
          static_cast  <  Derived  *>  (  this  )  ->  реализация  (); 
           // ... 
     } 
 }; 

 структура    производная   :   base  <derived>  {  voidimplementation 
 ( 
      ;   //  ) 
      { 
          ... 
      } 
 } 

Здесь шаблон базового класса будет использовать тот факт, что тела функций-членов не создаются до тех пор, пока они не будут объявлены, и он будет использовать члены производного класса в своих собственных функциях-членах посредством использования static_cast, таким образом, при компиляции генерируется композиция объектов с полиморфными характеристиками. В качестве примера реального использования CRTP используется в Boost библиотеке итераторов . [5]

Другое подобное использование — это « трюк Бартона-Нэкмана », иногда называемый «ограниченным расширением шаблона», когда общие функциональные возможности могут быть помещены в базовый класс, который используется не как контракт, а как необходимый компонент для обеспечения соответствующего поведения при минимизации избыточность кода.

Генерация статической таблицы [ править ]

Преимущество статических таблиц — замена «дорогих» вычислений простой операцией индексации массива (примеры см. в справочной таблице ). В C++ существует несколько способов создания статической таблицы во время компиляции. В следующем листинге показан пример создания очень простой таблицы с использованием рекурсивных структур и шаблонов с переменным числом вариантов . Стол имеет размер десять. Каждое значение представляет собой квадрат индекса.

#include   <iostream> 
 #include   <array> 

 constexpr   int   TABLE_SIZE   =   10  ; 

  /** 
 * Вариативный шаблон для рекурсивной вспомогательной структуры. 
  */ 
 template  <  int   INDEX   =   0  ,   int   ...  D  > 
 struct   Helper   :   Helper  <  INDEX   +   1  ,   D  ...,   INDEX   *   INDEX  >   {   }; 

  /** 
 * Специализация шаблона для завершения рекурсии, когда размер таблицы достигает TABLE_SIZE. 
  */ 
 template  <  int   ...  D  > 
 struct   Helper  <  TABLE_SIZE  ,   D  ...  >   { 
   static   constexpr   std  ::  array  <  int  ,   TABLE_SIZE  >   table   =   {   D  ...   }; 
  }; 

  constexpr   std  ::  массив  <  int  ,   TABLE_SIZE  >   table   =   Helper  <>::  table  ; 

  enum    { 
   FOUR   =   table  [  2  ]   // использование времени компиляции 
 }; 

  int   main  ()   { 
   for   (  int   i  =  0  ;   i   <   TABLE_SIZE  ;   i  ++  )   { 
     std  ::  cout   <<   table  [  i  ]    <<   std  ::  endl  ;    // использование во время выполнения 
   } 
   std  ::  cout   <<   "FOUR: "   <<   FOUR   <<   std  ::  endl  ; 
  } 

Идея заключается в том, что struct Helper рекурсивно наследуется от структуры с еще одним аргументом шаблона (в этом примере вычисляется как INDEX * INDEX), пока специализация шаблона не завершит рекурсию при размере 10 элементов. Специализация просто использует список переменных аргументов в качестве элементов массива. Компилятор создаст код, аналогичный следующему (взятый из clang, вызванного с помощью -Xclang -ast-print -fsyntax-only).

шаблон   <  int   INDEX   =   0  ,   int   ...  D  >   struct   Helper   :   Helper  <  INDEX   +   1  ,   D  ...,   INDEX   *   INDEX  >   { 
 }; 
  шаблон  <>   struct   Helper  <  0  ,   <>>   :   Helper  <  0   +   1  ,   0   *   0  >   { 
 }; 
  шаблон  <>   struct   Helper  <  1  ,   <  0  >>   :   Helper  <  1   +   1  ,   0  ,   1   *   1  >   { 
 }; 
  шаблон  <>   struct   Helper  <  2  ,   <  0  ,   1  >>   :   Helper  <  2   +   1  ,   0  ,   1  ,   2   *   2  >   { 
 }; 
  шаблон  <>   struct   Helper  <  3  ,   <  0  ,   1  ,   4  >>   :   Helper  <  3   +   1  ,   0  ,   1  ,   4  ,   3   *   3  >   { 
 }; 
  шаблон  <>   struct   Helper  <  4  ,   <  0  ,   1  ,   4  ,   9  >>   :   Helper  <  4   +   1  ,   0  ,   1  ,   4  ,   9  ,   4   *   4  >   { 
 }; 
  шаблон  <>   struct   Helper  <  5  ,   <  0  ,   1  ,   4  ,   9  ,   16  >>   :   Helper  <  5   +   1  ,   0  ,   1  ,   4  ,   9  ,   16  ,   5   *   5  >   { 
 }; 
  шаблон  <>   struct   Helper  <  6  ,   <  0  ,   1  ,   4  ,   9  ,   16  ,   25  >>   :   Helper  <  6   +   1  ,   0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   6   *   6  >   { 
 }; 
  template  <>   struct   Helper  <  7  ,   <  0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  >>   :   Helper  <  7   +   1  ,   0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   7   *   7  >   { 
 }; 
  шаблон  <>   struct   Helper  <  8  ,   <  0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   49  >>   :   Helper  <  8   +   1  ,   0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   49  ,   8   *   8  >   { 
 }; 
  шаблон  <>   struct   Helper  <  9  ,   <  0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   49  ,   64  >>   :   Helper  <  9   +   1  ,   0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   49  ,   64  ,   9   *   9  >   { 
 }; 
  template  <>   struct   Helper  <  10  ,   <  0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   49  ,   64  ,   81  >>   { 
   static   constexpr   std  ::  array  <  int  ,   TABLE_SIZE  >   table   =   {  0  ,   1  ,   4  ,   9  ,   16  ,   25  ,   36  ,   49  ,   64  ,   81  }; 
  }; 

Начиная с C++17, это можно более читабельно записать так:

 
#include   <iostream> 
 #include   <array> 

 constexpr   int   TABLE_SIZE   =   10  ; 

  constexpr   std  ::  array  <  int  ,   TABLE_SIZE  >   table   =   []   {   // ИЛИ: constexpr auto table 
   std  ::  array  <  int  ,   TABLE_SIZE  >   A   =   {}; 
    for   (  беззнаковый   я   =   0  ;   я   <   TABLE_SIZE  ;   я  ++  )   { 
     A  [  я  ]   =   я   *   я  ; 
    } 
   Вернуть   А  ; 
  }(); 

  enum    { 
   FOUR   =   table  [  2  ]   // использование времени компиляции 
 }; 

  int   main  ()   { 
   for   (  int   i  =  0  ;   i   <   TABLE_SIZE  ;   i  ++  )   { 
     std  ::  cout   <<   table  [  i  ]    <<   std  ::  endl  ;    // использование во время выполнения 
   } 
   std  ::  cout   <<   "FOUR: "   <<   FOUR   <<   std  ::  endl  ; 
  } 

Чтобы показать более сложный пример, код в следующем листинге был расширен и теперь имеет помощник для вычисления значений (при подготовке к более сложным вычислениям), смещение для конкретной таблицы и аргумент шаблона для типа значений таблицы (например, uint8_t, uint16_t, ...).

                                                                
#include   <iostream> 
 #include   <array> 

 constexpr   int   TABLE_SIZE   =   20  ; 
  constexpr   int   OFFSET   =   12  ; 

  /** 
 * Шаблон для расчета одной записи таблицы 
 */ 
 template   <  имя типа   VALUETYPE  ,   VALUETYPE   OFFSET  ,   VALUETYPE   INDEX  > 
 struct   ValueHelper   { 
   static   constexpr   VALUETYPE   value   =   OFFSET   +   INDEX   *   INDEX  ; 
  }; 

  /** 
 * Вариативный шаблон для рекурсивной вспомогательной структуры. 
  */ 
 template  <  имя типа   VALUETYPE  ,   VALUETYPE   OFFSET  ,   int   N   =   0  ,   VALUETYPE   ...  D  > 
 struct   Helper   :   Helper  <  VALUETYPE  ,   OFFSET  ,   N  +  1  ,   D  ...,   ValueHelper  <  VALUETYPE  ,   OFFSET  ,   N  >::  value  >   {   }; 

  /** 
 * Специализация шаблона для завершения рекурсии, когда размер таблицы достигает TABLE_SIZE. 
  */ 
 template  <  имя типа   VALUETYPE  ,   VALUETYPE   OFFSET  ,   VALUETYPE   ...  D  > 
 struct   Helper  <  VALUETYPE  ,   OFFSET  ,   TABLE_SIZE  ,   D  ...  >   { 
   static   constexpr   std  ::  array  <  VALUETYPE  ,   TABLE_SIZE  >   table   =   {   D  ...   } ; 
  }; 

  constexpr   std  ::  array  <  uint16_t  ,   TABLE_SIZE  >   table   =   Helper  <  uint16_t  ,   OFFSET  >::  table  ; 

  int   main  ()   { 
   for   (  int   i   =   0  ;   i   <   TABLE_SIZE  ;   i  ++  )   { 
     std  ::  cout   <<   table  [  i  ]   <<   std  ::  endl  ; 
    } 
 } 

Это можно записать следующим образом, используя C++17:

#include   <iostream> 
 #include   <array> 

 constexpr   int   TABLE_SIZE   =   20  ; 
  constexpr   int   OFFSET   =   12  ; 

  template  <  имя типа   VALUETYPE  ,   int   OFFSET  > 
 constexpr   std  ::  array  <  VALUETYPE  ,   TABLE_SIZE  >   table   =   []   {   // ИЛИ: constexpr auto table 
   std  ::  array  <  VALUETYPE  ,   TABLE_SIZE  >   A   =   {}; 
    for   (  беззнаковый   я   =   0  ;   я   <   TABLE_SIZE  ;   я  ++  )   { 
     A  [  я  ]   =   СМЕЩ   +   я   *   я  ; 
    } 
   Вернуть   А  ; 
  }(); 

  int   main  ()   { 
   for   (  int   i   =   0  ;   i   <   TABLE_SIZE  ;   i  ++  )   { 
     std  ::  cout   <<   table  <  uint16_t  ,   OFFSET  >  [  i  ]   <<   std  ::  endl  ; 
    } 
 } 

Концепции [ править ]

Стандарт C++20 предоставил программистам C++ новый инструмент для программирования меташаблонов — концепции. [6]

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

Вот пример знаменитой проблемы Fizz Buzz, решенной с помощью шаблонного метапрограммирования.

#include   <boost/type_index.hpp>  // для красивой печати типов 
 #include   <iostream> 
 #include   <tuple> 

 /** 
 * Типовое представление слов для печати 
 */ 
 struct   Fizz   {}; 
  структура   Buzz   {}; 
  структура   FizzBuzz   {}; 
  шаблон  <  size_t   _N  >   структуры   номер   {   constexpr   static   size_t   N   =   _N  ;    }; 

  /** 
 * Концепции, используемые для определения условий для специализаций 
 */ 
 template  <  typename   Any  >   Concept   has_N   =   require  {   require   Any  ::  N   -   Any  ::  N   ==   0  ;    }; 
  шаблон  <  имя типа   A  >   концепция   fizz_c   =   has_N  <  A  >   &&   требует  {   требует   A  ::  N   %   3   ==   0  ;    }; 
  шаблон  <  имя типа   A  >   концепция   buzz_c   =   has_N  <  A  >   &&   требует  {   требует   A  ::  N   %   5   ==   0  ;}; 
  шаблон  <  имя типа   A  >   концепция   fizzbuzz_c   =   fizz_c  <  A  >   &&   buzz_c  <  A  >  ; 

  /** 
 * Путем специализации структуры `res` с учетом требований концепции выполняется правильное создание экземпляров 
 */ 
 template  <  typename   X  >   struct   res  ; 
  шаблон  <  fizzbuzz_c   X  >   struct   res  <X>   {   using   result   =   FizzBuzz  ;    }; 
  шаблон  <  fizz_c   X  >   struct   res  <X>   {   using   result   =   Fizz  ;    }; 
  шаблон  <  buzz_c   X  >   struct   res  <X>   {   using   result   =   Buzz  ;    }; 
  шаблон  <  has_N   X  >   struct   res  <X>   {   using   result   =   X  ;    }; 

  /** 
 * Предварительное объявление конкатенатора 
 */ 
 template   <  size_t   cnt  ,   typename  ...   Args  >  
 struct   concatenator ; 

  /** 
 * Рекурсивный способ объединения следующих типов 
 */ 
 template   <  size_t   cnt  ,   typename   ...   Args  > 
 struct   concatenator  <  cnt  ,   std  ::  tuple  <  Args  ...  >>  
 {   using   type   =   typename   concatenator  <  cnt   -   1  ,   std  ::  tuple  <   typename   res  <   number  <  cnt  >   >::  result  ,   Args  ...   >>::  type  ;}; 

  /** 
 * Базовый случай 
 */ 
 template   <  typename  ...   Args  >   struct   concatenator  <  0  ,   std  ::  tuple  <  Args  ...  >>   {   using   type   =   std  ::  tuple  <  Args  ...  >  ;}; 

  /** 
 * Метод получения окончательного результата 
 */ 
 template  <  size_t   Amount  > 
 using   fizz_buzz_full_template   =   typename   concatenator  <  Amount   -   1  ,   std  ::  tuple  <  typename   res  <  Number  <  Amount  >>::  result  >>::  type  ; 

  int   main  () 
 { 
	 // результат печати с помощью boost, чтобы он был понятен 
	 std  ::  cout   <<   boost  ::  typeindex  ::  type_id  <  fizz_buzz_full_template  <  100  >>  ().   красивое_имя  ()   <<   std  ::  endl  ; 
  /* 
 Результат: 
 std::tuple<number<1ul>, Number<2ul>, Fizz, Number<4ul>, Buzz, Fizz, Number<7ul>, Number<8ul>, Fizz, Buzz, Number<11ul>, Fizz , номер<13ul>, номер<14ul>, FizzBuzz, номер<16ul>, номер<17ul>, Fizz, номер<19ul>, Buzz, Fizz, номер<22ul>, номер<23ul>, Fizz, Buzz, номер< 26ul>, Fizz, номер<28ul>, номер<29ul>, FizzBuzz, номер<31ul>, номер<32ul>, Fizz, номер<34ul>, Buzz, Fizz, номер<37ul>, номер<38ul>, Fizz, Buzz, номер<41ul>, Fizz, номер<43ul>, номер<44ul>, FizzBuzz, номер<46ul>, номер<47ul>, Fizz, номер<49ul>, Buzz, Fizz, номер<52ul>, номер<53ul >, Fizz, Buzz, номер<56ul>, Fizz, номер<58ul>, номер<59ul>, FizzBuzz, номер<61ul>, номер<62ul>, Fizz, номер<64ul>, Buzz, Fizz, номер<67ul> , номер<68ul>, Fizz, Buzz, номер<71ul>, Fizz, номер<73ul>, номер<74ul>, FizzBuzz, номер<76ul>, номер<77ul>, Fizz, номер<79ul>, Buzz, Fizz, номер<82ul>, номер<83ul>, Fizz, Buzz, номер<86ul>, Fizz, номер<88ul>, номер<89ul>, FizzBuzz, номер<91ul>, номер<92ul>, Fizz, номер<94ul>, Buzz, Fizz, номер <97ul>, номер <98ul>, Fizz, Buzz> 
*/ 
} 

метапрограммирования шаблонов Преимущества и недостатки

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

  • Метапрограммирование шаблонов позволяет программисту сосредоточиться на архитектуре и делегировать компилятору создание любой реализации, необходимой клиентскому коду. Таким образом, метапрограммирование шаблонов позволяет создавать действительно универсальный код , что способствует минимизации кода и повышению удобства сопровождения. [ нужна цитата ] .
  • Что касается C++ до версии C++11 , синтаксис и идиомы метапрограммирования шаблонов были эзотерическими по сравнению с обычным программированием C++, и метапрограммы шаблонов могли быть очень трудными для понимания. [7] [8] Но начиная с C++11 синтаксис метапрограммирования вычислений значений становится все более и более похожим на «нормальный» C++, с все меньшим и меньшим ухудшением читаемости.

См. также [ править ]

Ссылки [ править ]

  1. ^ Скотт Мейерс (12 мая 2005 г.). Эффективный C++: 55 конкретных способов улучшить ваши программы и проекты . Пирсон Образование. ISBN  978-0-13-270206-5 .
  2. ^ См. Историю TMP в Wikibooks.
  3. ^ Вельдхуизен, Тодд Л. (2003). «Шаблоны C++ полны по Тьюрингу». CiteSeerX   10.1.1.14.3670 .
  4. ^ «Constexpr — Обобщенные константные выражения в C++11 — Cprogramming.com» . www.cprogramming.com .
  5. ^ «Фасад Итератора — 1.79.0» .
  6. ^ «Ограничения и концепции (начиная с C++20) — cppreference.com» . ru.cppreference.com .
  7. ^ Чарнецкий, К.; О'Доннелл, Дж.; Стригниц, Дж.; Таха, Валид Мохамед (2004). «Реализация DSL в метаокамле, шаблоне Haskell и C++» (PDF) . Университет Ватерлоо, Университет Глазго, Исследовательский центр Юлиха, Университет Райса. Метапрограммирование шаблонов C++ страдает от ряда ограничений, в том числе проблем с переносимостью из-за ограничений компилятора (хотя за последние несколько лет ситуация значительно улучшилась), отсутствия поддержки отладки или ввода-вывода во время создания экземпляра шаблона, длительного времени компиляции, длинных и непонятных ошибок, плохой читаемость кода и плохая отчетность об ошибках.
  8. ^ Шеард, Тим; Джонс, Саймон Пейтон (2002). «Шаблон метапрограммирования для Haskell» (PDF) . АСМ 1-58113-415-0/01/0009. В провокационной статье Робинсона шаблоны C++ названы главным, хотя и случайным, успехом разработки языка C++. Несмотря на чрезвычайно причудливую природу метапрограммирования шаблонов, шаблоны используются удивительными способами, выходящими за рамки самых смелых мечтаний разработчиков языка. Возможно, это удивительно, но, учитывая тот факт, что шаблоны являются функциональными программами, функциональные программисты не спешат извлекать выгоду из успеха C++.

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: 6F78EE2381C6A6317D586830CD6E5A0C__1717008000
URL1:https://en.wikipedia.org/wiki/Template_metaprogramming
Заголовок, (Title) документа по адресу, URL1:
Template metaprogramming - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)