<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://mit.spbau.ru/sewiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Aleksandr.kartashov</id>
		<title>SEWiki - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://mit.spbau.ru/sewiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Aleksandr.kartashov"/>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Aleksandr.kartashov"/>
		<updated>2026-04-08T21:21:45Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.26.2</generator>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=Unix_%D0%B8_%D0%A1%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B8_2012&amp;diff=2035</id>
		<title>Unix и Скриптовые языки 2012</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=Unix_%D0%B8_%D0%A1%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%B2%D1%8B%D0%B5_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B8_2012&amp;diff=2035"/>
				<updated>2012-11-26T21:50:55Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: /* Задание по модулям Python */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Лектор - Кузнецов Антон Михайлович&lt;br /&gt;
&lt;br /&gt;
== Лекции. ==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 1&lt;br /&gt;
 |04.09.2012&lt;br /&gt;
 |История UNIX&lt;br /&gt;
 |Слайды [[Медиа:Unix2012-01.pdf|PDF]]&lt;br /&gt;
 |[[Медиа:Unix2012-Test01.pdf|Тест]]&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 2&lt;br /&gt;
 |07.09.2012&lt;br /&gt;
 |Введение в команды UNIX&lt;br /&gt;
 |Слайды [[Медиа:Unix2012-02.pdf|PDF]]&lt;br /&gt;
 |- &lt;br /&gt;
!Лекция 3&lt;br /&gt;
 |14.09.2012&lt;br /&gt;
 |Регулярные выражения. Sed, grep&lt;br /&gt;
 |Слайды [[Медиа:Unix2012-03.pdf|PDF]]&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 4&lt;br /&gt;
 |21.09.2012&lt;br /&gt;
 |Bash scripts&lt;br /&gt;
 |Слайды [[Медиа:Unix2012-04.pdf|PDF]] [http://gordin.us/sergo/abs-guide/x4165.html Работа со строками]&lt;br /&gt;
 |[[Домашнее_задание_&amp;quot;Unix_и_Скриптовые_языки&amp;quot;_2012|Задание]]&lt;br /&gt;
 |-&lt;br /&gt;
!Контрольная&lt;br /&gt;
 |28.09.2012&lt;br /&gt;
 |[https://docs.google.com/document/pub?id=1sF9Nmr2hIF84YcfP-KPkEzvFfmnvOScFvqA1mGNwcqs Задачи]&lt;br /&gt;
 |&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 4&lt;br /&gt;
 |19.10.2012&lt;br /&gt;
 |Python введение&lt;br /&gt;
 |Слайды [[Медиа:Unix-2012-07-Python.pdf|PDF]]&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 5&lt;br /&gt;
 |26.10.2012&lt;br /&gt;
 |Python строки&lt;br /&gt;
 |Слайды [[Медиа:Unix-2012-08-Python.pdf|PDF]]&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 6&lt;br /&gt;
 |2.11.2012&lt;br /&gt;
 |Python модули, итераторы&lt;br /&gt;
 |Слайды [[Медиа:Unix_2012_09_Modules.pdf|PDF]] [[Медиа:Unix_2012_09_Iterators.pdf|PDF]]&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
!Контрольная&lt;br /&gt;
 |9.11.2012&lt;br /&gt;
 |Тест [[Медиа:Test.pdf|PDF]]&lt;br /&gt;
 |&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 7&lt;br /&gt;
 |16.11.2012&lt;br /&gt;
 |Python ООП&lt;br /&gt;
 |Слайды [[Медиа:Unix_Slides_20111117.pdf |PDF]]&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
!Лекция 8&lt;br /&gt;
 |23.11.2012&lt;br /&gt;
 |Python ООП&lt;br /&gt;
 |Слайды [[Unix_20121123|Задание]] [[PDF]]&lt;br /&gt;
 |&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
== Зачет по Bash ==&lt;br /&gt;
&lt;br /&gt;
Для зачета контрольной необходимо набрать не менее 10 баллов! &amp;lt;br /&amp;gt;&lt;br /&gt;
Стоимость одной задачи на контрольной - 2 балла. &amp;lt;br /&amp;gt;&lt;br /&gt;
До 23:59 30 сентября - 1 балл. &amp;lt;br /&amp;gt;&lt;br /&gt;
После - 0.5 балла.&lt;br /&gt;
&lt;br /&gt;
== Задачи по Bash для &amp;quot;должников&amp;quot; ==&lt;br /&gt;
&lt;br /&gt;
Данные задачи необходимо решить для того, чтобы получить допуск для сдачи зачета! Зачет будет состоять из беседы и решения нескольких задач (часть из них в течение ограниченного времени в присутствии преподавателя).&lt;br /&gt;
&lt;br /&gt;
# Найдите, сколько времени прошло с момента создания самого старого до создания самого молодого файла на компьютере.&lt;br /&gt;
# Напишите скрипт, принимающий в качестве параметра каталог. Задача скрипта состоит в том, чтобы изменить имя каждого файла в каталоге и подкаталогах дописав в начало число, равное глубине вложенности файла. Например, файл A/B/C/x.txt должен превратиться в A/B/C/3x.txt.&lt;br /&gt;
# Напишите визуализатор сортировки пузырьком. При визуализации каждый элемент массива отображается столбиком из символов '#'. Высота столбика совпадает со значением элемента массива. Два столбика, соответствующие элементам, которые сравниваются в данный момент, должны отличаться по цвету от остальных.&lt;br /&gt;
&lt;br /&gt;
Вариант для тех, кому разрешили делать &amp;quot;эти&amp;quot; задачи:&lt;br /&gt;
&lt;br /&gt;
# Пусть у вас есть кластер состоящий из большого числа узлов. Список узлов находится в файле nodes.txt. Часто возникает ситуация завести нового пользователя и прописать его на всех узлах (это происходит там, где кто-то не знает, что можно использовать, например, LDAP ^) ). Ваша задача -- написать скрипт, который после запуска получает от пользователя все необходимые данные для создания нового пользователя и создает такого пользователя на всех узлах кластера.&lt;br /&gt;
# Напишите интерактивную утилиту для работы с XEN. Должны поддерживаться следующие возможности - запуск и остановка виртуальной машины; доступ к консоли виртуальной машины; вывод информации о занятости дисков виртуальных машин; разворачивание новой виртуальной машины из образа при этом задаются новые имя компьютера и его IP адрес.&lt;br /&gt;
&lt;br /&gt;
== Задание по модулям Python ==&lt;br /&gt;
# NamPy, SciPy, Matplotlib: Чаднов, Сонина, Шабалин, Плахотник, Монцев&lt;br /&gt;
# PIL: Аверьянов, Осипов&lt;br /&gt;
# NetworkX: Орлов, Ломшаков, Таланов, Служаев&lt;br /&gt;
# Socket: Пивоваров&lt;br /&gt;
# SMTPlib, POPlib: Пальчиков&lt;br /&gt;
# pyQwt: Козятинский, Карташов&lt;br /&gt;
# thread, threading:&lt;br /&gt;
# pyGame: Токарев, Сторожев (''как альтернатива - есть ещё движок Panda3d, там тоже можно на Python писать'')&lt;br /&gt;
&lt;br /&gt;
== Рейтинг ==&lt;br /&gt;
* [https://docs.google.com/spreadsheet/pub?key=0Aif17q2hwUt4dEdwVXVZX3ZzVGJUY1ZiaEpjSG52SHc&amp;amp;output=html Рейтинг.]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=LinuxKernelProgramming&amp;diff=1226</id>
		<title>LinuxKernelProgramming</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=LinuxKernelProgramming&amp;diff=1226"/>
				<updated>2012-03-28T11:50:42Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Лектор - Кринкин Кирилл Владимирович&lt;br /&gt;
&lt;br /&gt;
== Подготовка к работе ==&lt;br /&gt;
&lt;br /&gt;
Все работы рекомендуется проводить в виртуальном окружении, для этого можно использовать [https://www.virtualbox.org/wiki/Downloads VirtualBox].&lt;br /&gt;
&lt;br /&gt;
Для сдачи работ должен использовать git на гуглкоде http://code.google.com/p/linux-kernel-course/&lt;br /&gt;
&lt;br /&gt;
Для этого скачиваем ядро, &lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
и откатываемся к коммиту '''c579bc7e316e7e3f3b56df5e17f623325caa9783'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git reset --hard c579bc7e316e7e3f3b56df5e17f623325caa9783&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
а в конце отсылаем результаты домашней работы в формате, полученном командой&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git format-patch c579bc7e316e7e3f3b56df5e17f623325caa9783 &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Либо, не откатываемся к коммиту, а делаем от него ветку&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout c579bc7e316e7e3f3b56df5e17f623325caa9783 -b spbau-lkp&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
и делаем патч&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git format-patch master&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Установка OpenSSH-Server в VirtualBox ===&lt;br /&gt;
Для того, чтобы получить возможность пользоваться буфером обмена (вставлять текст в консоль) и не ставить VirtualBox Guest Additions, можно установить в виртуальную машину OpenSSH-Server, и подключаться к нему любым SSH клиентом.&lt;br /&gt;
Для этого необходимо добавить новую сетевую карту в виртуальную машину. Это делается в настройках, ДО ВКЛЮЧЕНИЯ виртуальной машины: в настройках нужно перейти на страницу с настройками сети, перейти на вкладку со вторым адаптером (первый адаптер используется виртуальной машиной для доступа к интернет через NAT) и выбрать подключение &amp;quot;Host-only adapter&amp;quot; (смотри пример на картинке).&lt;br /&gt;
&lt;br /&gt;
[[Файл:HostOnlyAdapter.png|Настройка дополнительной сетевой карты в VirtualBox]]&lt;br /&gt;
&lt;br /&gt;
Если VirtualBox выдает ошибку при выборе &amp;quot;Host-only Adapter&amp;quot;, то вероятнее всего это связано с тем, что не установлен виртуальный адаптер. Добавить его можно в сетевых настройках VirtualBox (File-&amp;gt;Preferences-&amp;gt;Networks).&lt;br /&gt;
&lt;br /&gt;
[[Файл:VBoxSettings-Network-2012.png|Добавление виртуального адаптера]]&lt;br /&gt;
&lt;br /&gt;
Теперь необходимо включить на этой сетевой карте возможность получить IP адрес по DHCP. Для этого нужно выполнить следующие две команды (предполагается, что в системе до этого была только одна сетевая карта):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
echo 'allow-hotplug eth1' &amp;gt;&amp;gt; /etc/network/interfaces&lt;br /&gt;
echo 'iface eth1 inet dhcp' &amp;gt;&amp;gt; /etc/network/interfaces&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
и установить OpenSSH-Server&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get install openssh-server&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Теперь можно из основной системы произвести подключение к виртуальной. Для этого нужно использовать SSH-клиент, такой как [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html  putty] которому нужно сообщить IP адрес виртуальной машины (его можно узнать командой ifconfig, и, скорее всего, это будет 192.168.56.101).&lt;br /&gt;
&lt;br /&gt;
[[Файл:PuttyConnect.png|Использование Putty для SSH соединения]]&lt;br /&gt;
&lt;br /&gt;
Важно помнить, что по умолчанию SSH не позволяет подключаться, используя учётную запись root. Если необходимы права суперпользователя, в начале подключитесь используя свою учётную запись на виртуальной машине (приняв перед этим сертификат безопасности), а потом используйте su.&lt;br /&gt;
&lt;br /&gt;
Так же рекомендуется в подпункте Translation пункта Window указывать UTF-8 в качестве Character set translation on received data - в частности, это необходимо для правильного отображения Midnight Commander.&lt;br /&gt;
&lt;br /&gt;
=== Сборка ядра 3.3.0-rc2 ===&lt;br /&gt;
Сборка ядра 3.3.0-rc2 (в соответствии с рекомендациями readme)&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
wget https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.3-rc2.tar.bz2&lt;br /&gt;
su -c &amp;quot;apt-get install bzip2&amp;quot;&lt;br /&gt;
tar -xjf linux-3.3-rc2.tar.bz2&lt;br /&gt;
cd linux-3.3-rc2/&lt;br /&gt;
mkdir -p ~/build/linux-3.3-rc2&lt;br /&gt;
su -c &amp;quot;apt-get install libncurses5-dev&amp;quot;&lt;br /&gt;
make O=~/build/linux-3.3-rc2 nconfig&lt;br /&gt;
make O=~/build/linux-3.3-rc2&lt;br /&gt;
su -c &amp;quot;make O=~/build/linux-3.3-rc2 modules_install install&amp;quot;&lt;br /&gt;
su -c &amp;quot;update-initramfs -c -v -k 3.3.0-rc2&amp;quot;&lt;br /&gt;
su -c &amp;quot;update-grub2&amp;quot;&lt;br /&gt;
shutdown -r now&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Использование patch ===&lt;br /&gt;
&lt;br /&gt;
== Создание модулей для ядра Linux ==&lt;br /&gt;
&lt;br /&gt;
=== Введение ===&lt;br /&gt;
&lt;br /&gt;
Некоторые отличия Ядра от программ, выполняемых в пространстве пользователя:&lt;br /&gt;
* Ядро LINUX пишется с расчётом на компилятор GNU C (разработчики ориентируются на стандарт ISO C99). В коде можно использовать ассемблерные вставки (директива ''asm()''), аннотацию ветвления (''likely()'' - более вероятная ветвь, ''unlikely()'' - менее вероятная) и весьма странный [http://www.kernel.org/doc/Documentation/CodingStyle кодстайл].&lt;br /&gt;
* Ядро не имеет доступа к стандартным библиотекам языка программирования C. Это сделано из соображений увеличения скорости выполнения и уменьшения объёма кода.&lt;br /&gt;
* Отсутствует защита памяти. Если обычная программа предпримет попытку некорректного обращения с памятью, то ядро сможет выгрузить такую программу, но если само ядро предпримет такую же попытку, то его будет некому проконтролировать. Так же важно помнить об отсутствии замещения страниц, т.е. каждому байту, используемому ядром, соответствует байт реальной физической памяти.&lt;br /&gt;
* В ядре используются только целочисленные вычисления. Это тоже сделано для ускорения работы, т.к. операции с плавающей точкой значительно более ресурсоёмки (в частности, активнее используются регистры CPU).&lt;br /&gt;
* Объём стека фиксирован, и обычно равен двум страницам памяти (8 Кбайт для x86, и 16 Кбайт для x64). По этой причине не рекомендуется использовать рекурсию.&lt;br /&gt;
* Важным требованием является переносимость - код должен компилироваться на максимально большом количестве систем.&lt;br /&gt;
&lt;br /&gt;
Загружаемый объект ядра называется '''модулем'''.&lt;br /&gt;
Динамическая загрузка и выгрузка модулей по мере необходимости появилась благодаря Питеру Мак-Дональду и впервые была представлена в версии ядра 0.99.&amp;lt;br&amp;gt;&lt;br /&gt;
По своей структуре, модуль похож на обычную прогамму (так же имеется точка входа, и необходима компиляция в бинарный вид) но имеет прямой доступ к структурам и функциям ядра, в то время как обычные программы такой доступ могут получить только через обёртки.&lt;br /&gt;
&lt;br /&gt;
=== Сборка модуля как отдельного объекта (Kernel object) ===&lt;br /&gt;
&lt;br /&gt;
==== Код модуля ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/module.h&amp;gt; // Этот файл подключается в любом модуле по соглашению&lt;br /&gt;
#include &amp;lt;linux/kernel.h&amp;gt; // Содержит макросы для функции printk()&lt;br /&gt;
#include &amp;lt;linux/init.h&amp;gt; // Содержит определения макросов __init и __exit&lt;br /&gt;
void printHW(void) // Функция для вывода приветствия&lt;br /&gt;
{&lt;br /&gt;
    printk(&amp;quot;Hello, world\n&amp;quot;); // выводит сообщение на экран и в лог messages&lt;br /&gt;
}&lt;br /&gt;
EXPORT_SYMBOL(printHW); // Экспорт функций ядра - предоставляет доступ к функции другим модулям ядра&lt;br /&gt;
static int __init start(void) // Точка входа в модуль&lt;br /&gt;
{&lt;br /&gt;
    printHW(); // Вызов функции&lt;br /&gt;
    return 0; // в случае успешной загрузки возвращать нулевое значение&lt;br /&gt;
}&lt;br /&gt;
static void __exit stop(void) // Точка выхода&lt;br /&gt;
{&lt;br /&gt;
    //printk(&amp;quot;Module unloaded\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
module_init(start);&lt;br /&gt;
module_exit(stop);&lt;br /&gt;
MODULE_LICENSE(&amp;quot;GPL&amp;quot;); // Указывает на лицензию, под которой распространяется данный модуль&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==== Сборка модуля (make) ====&lt;br /&gt;
&lt;br /&gt;
Файл с кодом модуля (myModule.c) должен находиться в одной папке с make-фалом, в котом должно быть написано&lt;br /&gt;
 obj-m += myModule.o&lt;br /&gt;
Тогда сборку модуля можно запустить командой&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make -C ./linux-3.3-rc2 SUBDIRS=$PWD modules&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Внимание, замените путь к исходным кодам ядра на тот, куда вы извлекли содержимое архива linux-3.3-rc2.tar.bz2&lt;br /&gt;
В итоге должен получиться файл модуля myModule.ko&lt;br /&gt;
&lt;br /&gt;
==== Загрузка модуля ====&lt;br /&gt;
&lt;br /&gt;
Теперь полученный модуль можно загрузить (эта команда требует прав суперпользователя). Для этого используется команда&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
insmod &amp;lt;имя модуля&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Список загруженных модулей хранится в /proc/modules (так что можно просмотреть этот файл cat /proc/modules) либо воспользоваться командой&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
lsmod&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Выгружать модуль можно командой (также требует прав суперпользователя)&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
rmmod &amp;lt;имя модуля&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Примечания ====&lt;br /&gt;
&lt;br /&gt;
Результат работы модуля выводится в /var/log/syslog, для его просмотра рекомендуется на отдельной консоли использовать&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tail -f /var/log/syslog&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Сборка модуля вместе с ядром (Kbuild) ===&lt;br /&gt;
&lt;br /&gt;
Модули для ядра можно собирать при помщи системы Kbuild. инструкции для сборки должны находиться в файле Kconfig.&lt;br /&gt;
&lt;br /&gt;
Что бы подключить наш Kconfig, нужно в файл linux-3.3-rc2/arch/x86/Kconfig.debug добавить строчку (рекомендуется сделать это где-нибудь в начле файла, например 6-й строкой)&lt;br /&gt;
 source &amp;quot;SPbAU/Kconfig&amp;quot;&lt;br /&gt;
Это позволит включать и отключать сборку наших модулей в меню '''Kernel hacking''', что в общем-то логично.&lt;br /&gt;
&lt;br /&gt;
Важно заметить, что если в makefile-файлах относительный путь задавался от места размещения самого файла, то в Kconfig - относительные пути строятся от корневого каталога дерева исходных кодов (в данном случае, от linux-3.3-rc2).&lt;br /&gt;
&lt;br /&gt;
Теперь, в дереве исходных кодов создаём каталог SPbAU, переносим туда (из предыдущего раздела) myModule.c и Makefile, а так же создаём файл Kconfig.&lt;br /&gt;
&lt;br /&gt;
==== Файл Kconfig ====&lt;br /&gt;
Файл Kconfig должен содержать следующий код&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
config SPbAU_KERNEL&lt;br /&gt;
	bool &amp;quot;Modules of students of the St. Petersburg Academic University of the Russian Academy of Sciences&amp;quot;&lt;br /&gt;
	default y&lt;br /&gt;
	---help---&lt;br /&gt;
	 SPbAU module list&lt;br /&gt;
&lt;br /&gt;
config SPbAU_KERNEL_PRINTHW&lt;br /&gt;
	tristate &amp;quot;The first module =)&amp;quot;&lt;br /&gt;
	depends on SPbAU_KERNEL&lt;br /&gt;
	default y&lt;br /&gt;
	---help---&lt;br /&gt;
	 Function prints the text &amp;quot;Hello, world&amp;quot; to the syslog file.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В первой строке мы объявляем о том, что хотим сделать раздел SPbAU_KERNEL (очень важно следить, что бы имена не перекрывались, по этому рационально использовать свой префикс, типа SPbAU). Потом мы указываем что пункт является bool, т.е. способен принимать значения Y или N (подробнее о значениях будет сказано чуть ниже), и определено имя этого раздела в меню. По умолчанию, раздел отмечен как ИСТИНА. Далее идёт справачная информация, которая может занимать несколько строк (необходимо соблюдать отступ в 1 пробел от основной линии).&lt;br /&gt;
&lt;br /&gt;
Потом мы описываем свой модуль. Ключевое слово ''tristate'' говорит о том, что этот пункт меню будет принимать одно из трёх возможных значения Y/M/N. Строчка depends on SPbAU_KERNEL показывает, что этот модуль не может быть установлен (и даже пункт не будет отображаться в меню), если в прерыщем пункте (SPbAU_KERNEL) стоит значение, отличное от истины. Это позволяет группировать различные элементы меню, уменьшая общую длинну списка.&lt;br /&gt;
&lt;br /&gt;
Возможные значения изначального состояния пунктов меню:&lt;br /&gt;
*Y - модуль вкомпилируется в ядро (это произайдёт успешно, если не допускать перекрытия имён точек входа)&lt;br /&gt;
*M - модуль компилируется отдельным файлом (kernel object)&lt;br /&gt;
*N - модуль не вкомпилируется&lt;br /&gt;
&lt;br /&gt;
Более подробно о языке формирования Kconfig файлов можно прочитать [http://kernel.org/doc/Documentation/kbuild/kconfig-language.txt здесь].&lt;br /&gt;
&lt;br /&gt;
==== Файл Makefile ====&lt;br /&gt;
&lt;br /&gt;
В Makefile необходимо добавить строчку&lt;br /&gt;
 obj-$(SPbAU_KERNEL_PRINTHW) += SPbAU/&lt;br /&gt;
&lt;br /&gt;
В файле Kconfig для мы указали tristate, т.е. пользователь может выбрать M и собрать отдельно модуль. Тогда команда ''make modules_install'' разместит .ko-файл в указанной директории (SPbAU), которая будет размещена по адресу /lib/modules/3.3.0-rc2/kernel/, т.е. общий путь к модулю будет /lib/modules/3.3.0-rc2/kernel/SPbAU/myModule.ko&lt;br /&gt;
&lt;br /&gt;
==== Сборка ядра с модулем ====&lt;br /&gt;
Вернувшись в корень дерева исходных кодов, вызываем меню&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make menuconfig&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это приведёт к выводу на экран графического меню&lt;br /&gt;
&lt;br /&gt;
[[Файл:Menuconfig.png‎|Вывод menuconfig]]&lt;br /&gt;
&lt;br /&gt;
Нас интересует раздел Kernel hacking, куда мы положили свои команды сборки модуля&lt;br /&gt;
&lt;br /&gt;
[[Файл:Menuconfig_Kernel_hacking.png‎|Вывод раздела Kernel hacking]]&lt;br /&gt;
&lt;br /&gt;
Отметка на пункте &amp;quot;Modules of students of the St. Petersburg Academic University of the Russian Academy of Sciences&amp;quot; позволяет скрывать все наши модули (в данном случае модуль всего 1), а отметка на пункте &amp;quot;The first module =)&amp;quot; может принимать как значение, соответствующее сборке отдального модуля, так и сборки внутри ядра.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Netlink ===&lt;br /&gt;
&lt;br /&gt;
Пример использования протокола Netlink из пространства пользователя&lt;br /&gt;
Программа, получающая список сетевых интерфейсов через RtNetlink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;sys/socket.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/netlink.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/rtnetlink.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// ================================================================================&lt;br /&gt;
&lt;br /&gt;
static char buf[10240];&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char** argv) {&lt;br /&gt;
  int nlsock;&lt;br /&gt;
  struct sockaddr_nl nla;&lt;br /&gt;
&lt;br /&gt;
  nlsock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);&lt;br /&gt;
  if (nlsock &amp;lt; 0) {&lt;br /&gt;
    printf(&amp;quot;Failed to create a Netlink socket: %s\n&amp;quot;, strerror(errno));&lt;br /&gt;
    return 1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  nla.nl_family = AF_NETLINK;&lt;br /&gt;
  nla.nl_pad = 0;&lt;br /&gt;
  nla.nl_pid = 0;&lt;br /&gt;
  nla.nl_groups = 0;&lt;br /&gt;
  if (connect(nlsock, (const struct sockaddr*)&amp;amp;nla, sizeof(nla)) &amp;lt; 0) {&lt;br /&gt;
    printf(&amp;quot;Failed to connect to the kernel rtnetlink: %s\n&amp;quot;, strerror(errno));&lt;br /&gt;
    goto close_sock;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  struct nlmsghdr* nlh = (struct nlmsghdr*)buf;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));&lt;br /&gt;
  nlh-&amp;gt;nlmsg_type = RTM_GETLINK;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_seq = 0;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_pid = getpid();&lt;br /&gt;
&lt;br /&gt;
  struct ifinfomsg* msg = (struct ifinfomsg*)NLMSG_DATA(nlh);&lt;br /&gt;
  msg-&amp;gt;ifi_family = AF_UNSPEC;&lt;br /&gt;
  msg-&amp;gt;ifi_index = 1;&lt;br /&gt;
  msg-&amp;gt;ifi_change = 0xFFFFFFFF;&lt;br /&gt;
&lt;br /&gt;
  if (send(nlsock, buf, nlh-&amp;gt;nlmsg_len, 0) &amp;lt; 0) {&lt;br /&gt;
    printf(&amp;quot;Failed to send a Netlink message: %s\n&amp;quot;, strerror(errno));&lt;br /&gt;
    goto close_sock;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  int sz = recv(nlsock, buf, sizeof(buf), 0);&lt;br /&gt;
&lt;br /&gt;
  while (NLMSG_OK(nlh, sz) &amp;amp;&amp;amp; nlh-&amp;gt;nlmsg_type != NLMSG_DONE) {&lt;br /&gt;
    if (nlh-&amp;gt;nlmsg_type &amp;amp; NLMSG_ERROR) {&lt;br /&gt;
      struct nlmsgerr* e = (struct nlmsgerr*)NLMSG_DATA(nlh);&lt;br /&gt;
      printf(&amp;quot;Failed to get a link: %d (%s)\n&amp;quot;, e-&amp;gt;error, strerror(-e-&amp;gt;error));&lt;br /&gt;
      goto close_sock;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (nlh-&amp;gt;nlmsg_type &amp;amp; RTM_NEWLINK) {&lt;br /&gt;
      struct rtattr* pattr;&lt;br /&gt;
      struct ifinfomsg* msg = (struct ifinfomsg*)NLMSG_DATA(nlh);&lt;br /&gt;
&lt;br /&gt;
      pattr = (struct rtattr*)(msg + 1);&lt;br /&gt;
      int alen = (char*)(nlh + nlh-&amp;gt;nlmsg_len) - (char*)pattr;&lt;br /&gt;
&lt;br /&gt;
      while (RTA_OK(pattr, alen)) {&lt;br /&gt;
        if (pattr-&amp;gt;rta_type == IFLA_IFNAME) {&lt;br /&gt;
          printf(&amp;quot;Interface %d, name %.*s\n&amp;quot;, msg-&amp;gt;ifi_index, RTA_PAYLOAD(pattr), RTA_DATA(pattr));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        pattr = RTA_NEXT(pattr, alen);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    nlh = NLMSG_NEXT(nlh, sz);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
 close_sock:&lt;br /&gt;
  close(nlsock);&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Список литературы ==&lt;br /&gt;
&lt;br /&gt;
* Разработка ядра Linux. Роберт Лав (http://www.ozon.ru/context/detail/id/2918313/)&lt;br /&gt;
* Ядро Linux. Д. Бовет, М. Чезати (http://www.ozon.ru/context/detail/id/3589107/)&lt;br /&gt;
* Linux Device Drivers, Джонатан Корбет, Алесандро Рубини, Грег Кроа-Хартман (http://lwn.net/Kernel/LDD3/) официаль&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=SE_Wiki/LKP&amp;diff=1225</id>
		<title>SE Wiki/LKP</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=SE_Wiki/LKP&amp;diff=1225"/>
				<updated>2012-03-28T11:48:40Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: Новая страница: «=Linux Kernel programming=  ==Netlink==  Пример использования протокола Netlink из пространства пользователя П…»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Linux Kernel programming=&lt;br /&gt;
&lt;br /&gt;
==Netlink==&lt;br /&gt;
&lt;br /&gt;
Пример использования протокола Netlink из пространства пользователя&lt;br /&gt;
Программа, получающая список сетевых интерфейсов через RtNetlink:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;sys/socket.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/netlink.h&amp;gt;&lt;br /&gt;
#include &amp;lt;linux/rtnetlink.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// ================================================================================&lt;br /&gt;
&lt;br /&gt;
static char buf[10240];&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char** argv) {&lt;br /&gt;
  int nlsock;&lt;br /&gt;
  struct sockaddr_nl nla;&lt;br /&gt;
&lt;br /&gt;
  nlsock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);&lt;br /&gt;
  if (nlsock &amp;lt; 0) {&lt;br /&gt;
    printf(&amp;quot;Failed to create a Netlink socket: %s\n&amp;quot;, strerror(errno));&lt;br /&gt;
    return 1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  nla.nl_family = AF_NETLINK;&lt;br /&gt;
  nla.nl_pad = 0;&lt;br /&gt;
  nla.nl_pid = 0;&lt;br /&gt;
  nla.nl_groups = 0;&lt;br /&gt;
  if (connect(nlsock, (const struct sockaddr*)&amp;amp;nla, sizeof(nla)) &amp;lt; 0) {&lt;br /&gt;
    printf(&amp;quot;Failed to connect to the kernel rtnetlink: %s\n&amp;quot;, strerror(errno));&lt;br /&gt;
    goto close_sock;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  struct nlmsghdr* nlh = (struct nlmsghdr*)buf;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));&lt;br /&gt;
  nlh-&amp;gt;nlmsg_type = RTM_GETLINK;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_seq = 0;&lt;br /&gt;
  nlh-&amp;gt;nlmsg_pid = getpid();&lt;br /&gt;
&lt;br /&gt;
  struct ifinfomsg* msg = (struct ifinfomsg*)NLMSG_DATA(nlh);&lt;br /&gt;
  msg-&amp;gt;ifi_family = AF_UNSPEC;&lt;br /&gt;
  msg-&amp;gt;ifi_index = 1;&lt;br /&gt;
  msg-&amp;gt;ifi_change = 0xFFFFFFFF;&lt;br /&gt;
&lt;br /&gt;
  if (send(nlsock, buf, nlh-&amp;gt;nlmsg_len, 0) &amp;lt; 0) {&lt;br /&gt;
    printf(&amp;quot;Failed to send a Netlink message: %s\n&amp;quot;, strerror(errno));&lt;br /&gt;
    goto close_sock;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  int sz = recv(nlsock, buf, sizeof(buf), 0);&lt;br /&gt;
&lt;br /&gt;
  while (NLMSG_OK(nlh, sz) &amp;amp;&amp;amp; nlh-&amp;gt;nlmsg_type != NLMSG_DONE) {&lt;br /&gt;
    if (nlh-&amp;gt;nlmsg_type &amp;amp; NLMSG_ERROR) {&lt;br /&gt;
      struct nlmsgerr* e = (struct nlmsgerr*)NLMSG_DATA(nlh);&lt;br /&gt;
      printf(&amp;quot;Failed to get a link: %d (%s)\n&amp;quot;, e-&amp;gt;error, strerror(-e-&amp;gt;error));&lt;br /&gt;
      goto close_sock;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (nlh-&amp;gt;nlmsg_type &amp;amp; RTM_NEWLINK) {&lt;br /&gt;
      struct rtattr* pattr;&lt;br /&gt;
      struct ifinfomsg* msg = (struct ifinfomsg*)NLMSG_DATA(nlh);&lt;br /&gt;
&lt;br /&gt;
      pattr = (struct rtattr*)(msg + 1);&lt;br /&gt;
      int alen = (char*)(nlh + nlh-&amp;gt;nlmsg_len) - (char*)pattr;&lt;br /&gt;
&lt;br /&gt;
      while (RTA_OK(pattr, alen)) {&lt;br /&gt;
        if (pattr-&amp;gt;rta_type == IFLA_IFNAME) {&lt;br /&gt;
          printf(&amp;quot;Interface %d, name %.*s\n&amp;quot;, msg-&amp;gt;ifi_index, RTA_PAYLOAD(pattr), RTA_DATA(pattr));&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        pattr = RTA_NEXT(pattr, alen);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    nlh = NLMSG_NEXT(nlh, sz);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
 close_sock:&lt;br /&gt;
  close(nlsock);&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=370</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=370"/>
				<updated>2011-09-16T16:27:45Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: /* Образование */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Карташов Александр ==&lt;br /&gt;
=== Контакты ===&lt;br /&gt;
* E-mail: [mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;br /&gt;
* Jabber: aleksandr.kartashov@jabber.org&lt;br /&gt;
* Skype: aleksandr.kartashov&lt;br /&gt;
&lt;br /&gt;
=== Образование ===&lt;br /&gt;
'''2006---2010''' Липецкий Государственный Технический университет, факультет автоматизации и информатики, кафедра автоматизированных систем управления.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=369</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=369"/>
				<updated>2011-09-16T16:27:09Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: /* Образование */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Карташов Александр ==&lt;br /&gt;
=== Контакты ===&lt;br /&gt;
* E-mail: [mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;br /&gt;
* Jabber: aleksandr.kartashov@jabber.org&lt;br /&gt;
* Skype: aleksandr.kartashov&lt;br /&gt;
&lt;br /&gt;
=== Образование ===&lt;br /&gt;
Липецкий Государственный Технический университет, факультет автоматизации и информатики, кафедра автоматизированных систем управления.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=368</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=368"/>
				<updated>2011-09-16T16:25:27Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Карташов Александр ==&lt;br /&gt;
=== Контакты ===&lt;br /&gt;
* E-mail: [mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;br /&gt;
* Jabber: aleksandr.kartashov@jabber.org&lt;br /&gt;
* Skype: aleksandr.kartashov&lt;br /&gt;
&lt;br /&gt;
=== Образование ===&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=367</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=367"/>
				<updated>2011-09-16T16:24:08Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Карташов Александр ==&lt;br /&gt;
=== Контакты ===&lt;br /&gt;
* E-mail: [mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;br /&gt;
* Jabber: aleksandr.kartashov@jabber.org&lt;br /&gt;
* Skype: aleksandr.kartashov&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=366</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=366"/>
				<updated>2011-09-16T16:23:16Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Карташов Александр ==&lt;br /&gt;
=== Контакты ===&lt;br /&gt;
* E-mail: [mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=365</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=365"/>
				<updated>2011-09-16T16:22:54Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Карташов Александр ==&lt;br /&gt;
=== Контакты ===&lt;br /&gt;
E-mail: [mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=364</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=364"/>
				<updated>2011-09-16T14:46:07Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[mailto:aleksandr.kartashov.aptu.se@gmail.com aleksandr.kartashov.aptu.se@gmail.com]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=363</id>
		<title>Участник:Aleksandr.kartashov</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Aleksandr.kartashov&amp;diff=363"/>
				<updated>2011-09-16T14:45:03Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: Новая страница: «[mailto:aleksandr.kartashov.aptu.se@gmail.com]»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[mailto:aleksandr.kartashov.aptu.se@gmail.com]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=343</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=343"/>
				<updated>2011-05-31T09:56:45Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
[http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo/quickref.html Строковые алгоритмы] Boost являются&lt;br /&gt;
обобщением и расширением методов строковых классов STL и алгоритмов STL, предназначенных для работы с последовательностями.&lt;br /&gt;
&lt;br /&gt;
* Преобразование регистра: &amp;lt;code&amp;gt;to_upper(input)&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;to_lower(iput)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Удаление пробельных символов в начале и в конце строки &amp;lt;code&amp;gt;trim_left[_if](input [, predicate])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trim_right[_if](input[, predicate]&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;trim[_if](input[, predicate])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Предикаты: &amp;lt;code&amp;gt;[i]strarts_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]ends_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]contains(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]equals(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]lexicographical_compare(range1, range2 [, comp])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы поиска: &amp;lt;code&amp;gt;[i]find_first(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_last(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_nth(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_regex(input, regex)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы замены: &amp;lt;code&amp;gt;[i][replace|erase]_first(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_last(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_nth(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_regex(input, regex [,format])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;split[_regex](result, input [, predicate | regex])&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;join(input, separator)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Функторы-классификаторы символов&lt;br /&gt;
&lt;br /&gt;
Существуют версии этих алгоритмов с суффиксом &amp;lt;code&amp;gt;_copy&amp;lt;/code&amp;gt;, которые выполняют те же действия над копией входной строки и возвращают ее.&lt;br /&gt;
&lt;br /&gt;
== Итераторы ==&lt;br /&gt;
&lt;br /&gt;
Библиотека [http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/index.html итераторов] Boost расширяет концепцию итераторов STL.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;counting_iterator&amp;lt;Incrementable&amp;gt;&amp;lt;/code&amp;gt; --- реализует концепцию &amp;lt;&amp;lt;ленивой&amp;gt;&amp;gt; последовательности --- итератор получает новое значение, выполняя операцию &amp;lt;code&amp;gt;Incrementable::operator++&amp;lt;/code&amp;gt; над обернутым объектом.&lt;br /&gt;
* &amp;lt;code&amp;gt;filter_iterator&amp;lt;Predicate, Iterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует подмножество значений обернутого итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;function_output_iterator&amp;lt;UnaryFunction&amp;gt;&amp;lt;/code&amp;gt; --- преобразует записываемое в итератор значение с помощью указанной функции.&lt;br /&gt;
* &amp;lt;code&amp;gt;indirect_iterator&amp;lt;Iterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует объекты, на которые указывают значения другого итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;permutation_iterator&amp;lt;ElementIterator, IndexIterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует по перестановкам значений итераторя ElementIterator, задаваемым итератором IndexIterator.&lt;br /&gt;
* &amp;lt;code&amp;gt;reverse_iterator&amp;lt;Iterator&amp;gt;&amp;lt;/code&amp;gt; --- расширение стандартного обратного итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_container_iterator&amp;lt;Container&amp;gt;&amp;lt;/code&amp;gt; --- продлевает жизнь захваченному контейнеру: пока существует итератор контейнер не будет уничтожен.&lt;br /&gt;
* &amp;lt;code&amp;gt;transform_iterator&amp;lt;UnaryFunction, Iterator&amp;gt;&amp;lt;/code&amp;gt; --- вызывает UnaryFunction над значением обернутого итератора при каждом разыменовании м возвращает результат.&lt;br /&gt;
* &amp;lt;code&amp;gt;zip_iterator&amp;lt;IteratorTuple&amp;gt;&amp;lt;/code&amp;gt; --- итерирует множество итераторов.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;lambda&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Модуль [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt;] библиотеки Boost является обобщением функций &amp;lt;code&amp;gt;std::bind1st&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;std::bind2nd&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
bind(g, _1, _1, _1)(x, y, z);     // g(x, x, x)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Модуль [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda/using_library.html &amp;lt;code&amp;gt;lambda&amp;lt;/code&amp;gt;] библиотеки Boost вводит концепцию безымянных функций.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=342</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=342"/>
				<updated>2011-05-31T09:53:03Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
[http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo/quickref.html Строковые алгоритмы] Boost являются&lt;br /&gt;
обобщением и расширением методов строковых классов STL и алгоритмов STL, предназначенных для работы с последовательностями.&lt;br /&gt;
&lt;br /&gt;
* Преобразование регистра: &amp;lt;code&amp;gt;to_upper(input)&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;to_lower(iput)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Удаление пробельных символов в начале и в конце строки &amp;lt;code&amp;gt;trim_left[_if](input [, predicate])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trim_right[_if](input[, predicate]&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;trim[_if](input[, predicate])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Предикаты: &amp;lt;code&amp;gt;[i]strarts_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]ends_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]contains(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]equals(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]lexicographical_compare(range1, range2 [, comp])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы поиска: &amp;lt;code&amp;gt;[i]find_first(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_last(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_nth(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_regex(input, regex)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы замены: &amp;lt;code&amp;gt;[i][replace|erase]_first(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_last(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_nth(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_regex(input, regex [,format])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;split[_regex](result, input [, predicate | regex])&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;join(input, separator)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Функторы-классификаторы символов&lt;br /&gt;
&lt;br /&gt;
Существуют версии этих алгоритмов с суффиксом &amp;lt;code&amp;gt;_copy&amp;lt;/code&amp;gt;, которые выполняют те же действия над копией входной строки и возвращают ее.&lt;br /&gt;
&lt;br /&gt;
== Итераторы ==&lt;br /&gt;
&lt;br /&gt;
Библиотека [http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/index.html итераторов] Boost расширяет концепцию итераторов STL.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;counting_iterator&amp;lt;Incrementable&amp;gt;&amp;lt;/code&amp;gt; --- реализует концепцию &amp;lt;&amp;lt;ленивой&amp;gt;&amp;gt; последовательности --- итератор получает новое значение, выполняя операцию &amp;lt;code&amp;gt;Incrementable::operator++&amp;lt;/code&amp;gt; над обернутым объектом.&lt;br /&gt;
* &amp;lt;code&amp;gt;filter_iterator&amp;lt;Predicate, Iterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует подмножество значений обернутого итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;function_output_iterator&amp;lt;UnaryFunction&amp;gt;&amp;lt;/code&amp;gt; --- преобразует записываемое в итератор значение с помощью указанной функции.&lt;br /&gt;
* &amp;lt;code&amp;gt;indirect_iterator&amp;lt;Iterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует объекты, на которые указывают значения другого итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;permutation_iterator&amp;lt;ElementIterator, IndexIterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует по перестановкам значений итераторя ElementIterator, задаваемым итератором IndexIterator.&lt;br /&gt;
* &amp;lt;code&amp;gt;reverse_iterator&amp;lt;Iterator&amp;gt;&amp;lt;/code&amp;gt; --- расширение стандартного обратного итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_container_iterator&amp;lt;Container&amp;gt;&amp;lt;/code&amp;gt; --- продлевает жизнь захваченному контейнеру: пока существует итератор контейнер не будет уничтожен.&lt;br /&gt;
* &amp;lt;code&amp;gt;transform_iterator&amp;lt;UnaryFunction, Iterator&amp;gt;&amp;lt;/code&amp;gt; --- вызывает UnaryFunction над значением обернутого итератора при каждом разыменовании м возвращает результат.&lt;br /&gt;
* &amp;lt;code&amp;gt;zip_iterator&amp;lt;IteratorTuple&amp;gt;&amp;lt;/code&amp;gt; --- итерирует множество итераторов.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;lambda&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Модуль [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html &amp;lt;code&amp;gt;bind&amp;lt;/code&amp;gt;] библиотеки Boost является обобщением функций &amp;lt;code&amp;gt;std::bind1st&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;std::bind2nd&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
bind(g, _1, _1, _1)(x, y, z);     // g(x, x, x)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=341</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=341"/>
				<updated>2011-05-31T09:47:49Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
[http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo/quickref.html Строковые алгоритмы] Boost являются&lt;br /&gt;
обобщением и расширением методов строковых классов STL и алгоритмов STL, предназначенных для работы с последовательностями.&lt;br /&gt;
&lt;br /&gt;
* Преобразование регистра: &amp;lt;code&amp;gt;to_upper(input)&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;to_lower(iput)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Удаление пробельных символов в начале и в конце строки &amp;lt;code&amp;gt;trim_left[_if](input [, predicate])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trim_right[_if](input[, predicate]&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;trim[_if](input[, predicate])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Предикаты: &amp;lt;code&amp;gt;[i]strarts_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]ends_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]contains(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]equals(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]lexicographical_compare(range1, range2 [, comp])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы поиска: &amp;lt;code&amp;gt;[i]find_first(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_last(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_nth(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_regex(input, regex)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы замены: &amp;lt;code&amp;gt;[i][replace|erase]_first(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_last(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_nth(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_regex(input, regex [,format])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;split[_regex](result, input [, predicate | regex])&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;join(input, separator)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Функторы-классификаторы символов&lt;br /&gt;
&lt;br /&gt;
Существуют версии этих алгоритмов с суффиксом &amp;lt;code&amp;gt;_copy&amp;lt;/code&amp;gt;, которые выполняют те же действия над копией входной строки и возвращают ее.&lt;br /&gt;
&lt;br /&gt;
== Итераторы ==&lt;br /&gt;
&lt;br /&gt;
Библиотека [http://www.boost.org/doc/libs/1_46_1/libs/iterator/doc/index.html итераторов] Boost расширяет концепцию итераторов STL.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;counting_iterator&amp;lt;Incrementable&amp;gt;&amp;lt;/code&amp;gt; --- реализует концепцию &amp;lt;&amp;lt;ленивой&amp;gt;&amp;gt; последовательности --- итератор получает новое значение, выполняя операцию &amp;lt;code&amp;gt;Incrementable::operator++&amp;lt;/code&amp;gt; над обернутым объектом.&lt;br /&gt;
* &amp;lt;code&amp;gt;filter_iterator&amp;lt;Predicate, Iterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует подмножество значений обернутого итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;function_output_iterator&amp;lt;UnaryFunction&amp;gt;&amp;lt;/code&amp;gt; --- преобразует записываемое в итератор значение с помощью указанной функции.&lt;br /&gt;
* &amp;lt;code&amp;gt;indirect_iterator&amp;lt;Iterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует объекты, на которые указывают значения другого итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;permutation_iterator&amp;lt;ElementIterator, IndexIterator&amp;gt;&amp;lt;/code&amp;gt; --- итерирует по перестановкам значений итераторя ElementIterator, задаваемым итератором IndexIterator.&lt;br /&gt;
* &amp;lt;code&amp;gt;reverse_iterator&amp;lt;Iterator&amp;gt;&amp;lt;/code&amp;gt; --- расширение стандартного обратного итератора.&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_container_iterator&amp;lt;Container&amp;gt;&amp;lt;/code&amp;gt; --- продлевает жизнь захваченному контейнеру: пока существует итератор контейнер не будет уничтожен.&lt;br /&gt;
* &amp;lt;code&amp;gt;transform_iterator&amp;lt;UnaryFunction, Iterator&amp;gt;&amp;lt;/code&amp;gt; --- вызывает UnaryFunction над значением обернутого итератора при каждом разыменовании м возвращает результат.&lt;br /&gt;
* &amp;lt;code&amp;gt;zip_iterator&amp;lt;IteratorTuple&amp;gt;&amp;lt;/code&amp;gt; --- итерирует множество итераторов.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=340</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=340"/>
				<updated>2011-05-31T09:23:31Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
[http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo/quickref.html Строковые алгоритмы] Boost являются&lt;br /&gt;
обобщением и расширением методов строковых классов STL и алгоритмов STL, предназначенных для работы с последовательностями.&lt;br /&gt;
&lt;br /&gt;
* Преобразование регистра: &amp;lt;code&amp;gt;to_upper(input)&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;to_lower(iput)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Удаление пробельных символов в начале и в конце строки &amp;lt;code&amp;gt;trim_left[_if](input [, predicate])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trim_right[_if](input[, predicate]&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;trim[_if](input[, predicate])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Предикаты: &amp;lt;code&amp;gt;[i]strarts_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]ends_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]contains(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]equals(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]lexicographical_compare(range1, range2 [, comp])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы поиска: &amp;lt;code&amp;gt;[i]find_first(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_last(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_nth(input, search)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]find_regex(input, regex)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Алгоритмы замены: &amp;lt;code&amp;gt;[i][replace|erase]_first(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_last(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_nth(input, search [, format])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i][replace|erase]_regex(input, regex [,format])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;split[_regex](result, input [, predicate | regex])&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;join(input, separator)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Функторы-классификаторы символов&lt;br /&gt;
&lt;br /&gt;
Существуют версии этих алгоритмов с суффиксом &amp;lt;code&amp;gt;_copy&amp;lt;/code&amp;gt;, которые выполняют те же действия над копией входной строки и возвращают ее.&lt;br /&gt;
&lt;br /&gt;
== Итераторы ==&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=339</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=339"/>
				<updated>2011-05-31T08:35:18Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
[http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo/quickref.html Строковые алгоритмы] Boost являются&lt;br /&gt;
обобщением и расширением методов строковых классов STL и алгоритмов STL, предназначенных для работы с последовательностями.&lt;br /&gt;
&lt;br /&gt;
* Преобразование регистра: &amp;lt;code&amp;gt;to_upper(input)&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;to_lower(iput)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Удаление пробельных символов в начале и в конце строки &amp;lt;code&amp;gt;trim_left[_if](input [, predicate])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trim_right[_if](input[, predicate]&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;trim[_if](input[, predicate])&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Предикаты: &amp;lt;code&amp;gt;[i]strarts_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]ends_with(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]contains(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]equals(range1, range2 [, comp])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[i]lexicographical_compare(range1, range2 [, comp])&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=338</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=338"/>
				<updated>2011-05-31T08:30:54Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;br /&gt;
&lt;br /&gt;
[http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo/quickref.html Строковые алгоритмы] Boost являются&lt;br /&gt;
обобщением и расширением методов строковых классов STL и алгоритмов STL, предназначенных для работы с последовательностями.&lt;br /&gt;
&lt;br /&gt;
* Преобразование регистра: &amp;lt;code&amp;gt;to_upper(input)&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;to_lower(iput)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Удаление пробельных символов в начале и в конце строки &amp;lt;code&amp;gt;trim_left[_if](input [, predicate])&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trim_right[_if](input[, predicate]&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;trim[_if](input[, predicate])/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=337</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=337"/>
				<updated>2011-05-31T08:20:25Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены]&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
** размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
** объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать от произвольного &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Версия &amp;lt;&amp;lt;умного&amp;gt;&amp;gt; указателя с суффиксом &amp;lt;code&amp;gt;_array&amp;lt;/code&amp;gt; управляет временем жизни массива, а не&lt;br /&gt;
отдельного объекта&lt;br /&gt;
&lt;br /&gt;
== Строковые алгоритмы ==&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=336</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=336"/>
				<updated>2011-05-31T08:16:10Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm представлены&lt;br /&gt;
в библиотеке Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;. Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt; были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
  * размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
  * объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=335</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=335"/>
				<updated>2011-05-31T08:15:01Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели представлены&lt;br /&gt;
в [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm библиотеке] Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
Следует отметить, что через этот указатель нельзя обратиться к объекту напрямую --- можно только создать&lt;br /&gt;
&amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;, указывающий на этот объект, с помощью метода &amp;lt;code&amp;gt;lock()&amp;lt;/code&amp;gt; --- если объект&lt;br /&gt;
уже уничтожен, то возвращается пустой &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; --- аналог &amp;lt;code&amp;gt;shared_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;; требует, чтобы у типа &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
были определены методы intrusive_ptr_add_ref() и intrusive_ptr_release(). У &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;, по&lt;br /&gt;
крайней мере, два преимущества перед &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;:&lt;br /&gt;
  * размер объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt; совпадает с размером указателя,&lt;br /&gt;
  * объекта &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; можно проинициализировать &amp;lt;code&amp;gt;T*&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=334</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=334"/>
				<updated>2011-05-31T08:03:57Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;br /&gt;
&lt;br /&gt;
Все рассмотренные в прошлом семестре &amp;lt;&amp;lt;умные&amp;gt; указатели представлены&lt;br /&gt;
в [http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm библиотеке] Boost.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;scoped_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;scoped_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;shared_array&amp;lt;/code&amp;gt;,&lt;br /&gt;
* &amp;lt;code&amp;gt;weak_ptr&amp;lt;/code&amp;gt; --- ссылка на объект, который находится под управлением &amp;lt;code&amp;gt;shared_ptr&amp;lt;/code&amp;gt;.&lt;br /&gt;
  Следует отметить, что &lt;br /&gt;
* &amp;lt;code&amp;gt;intrusive_ptr&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9A%D0%BE%D0%BD%D1%81%D0%BF%D0%B5%D0%BA%D1%82%D1%8B_%D0%A1%2B%2B&amp;diff=333</id>
		<title>Конспекты С++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9A%D0%BE%D0%BD%D1%81%D0%BF%D0%B5%D0%BA%D1%82%D1%8B_%D0%A1%2B%2B&amp;diff=333"/>
				<updated>2011-05-31T07:56:12Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 1 семестр (осень-зима 2010) ==&lt;br /&gt;
&lt;br /&gt;
* [[ Как происходит компиляция|Как происходит компиляция. Алексей Давыдов. 08.09.2010]]&lt;br /&gt;
* [[ Указатели и ссылки|Указатели и ссылки. Екатерина Полищук. 10.09.2010]]&lt;br /&gt;
* [[ Динамическое распределение памяти|Динамическое распределение памяти. Алексей Гуревич. 17.09.2010]]&lt;br /&gt;
* [[ Классы|Классы. Курьян Кристина. 08.10.2010]]&lt;br /&gt;
* [[ Перегрузка операторов|Перегрузка операторов. Мария Фомкина. 12.11.2010]]&lt;br /&gt;
* [[ Множественное наследование, дружба|Множественное наследование, дружба Евгений Баталов. 02.12.2010]]&lt;br /&gt;
&lt;br /&gt;
== 2 семестр (зима-весна 2011) ==&lt;br /&gt;
&lt;br /&gt;
* [[ Напоминание про inline и static. Синглтон.|Напоминание про inline и static. Синглтон. Екатерина Полищук. 11.02.2011]]&lt;br /&gt;
* [[ STL. Последовательные контейнеры|STL. Последовательные контейнеры. Мария Фомкина. 18.02.2011]]&lt;br /&gt;
* [[ Ассоциативные контейнеры |STL. Ассоциативные контейнеры. Светлана Марченко. 25.02.2011]]&lt;br /&gt;
* [[ Итераторы и алгоритмы | Итераторы и алгоритмы. Всеволод Опарин. 04.03.2011]]&lt;br /&gt;
* [[ Функторы. Namespaces | Функторы. Namespaces. Иван Близнец. 09.03.2011 ]]&lt;br /&gt;
* [[ Указатели на функции|Указатели на функции. Курьян Кристина. 18.03.2011]]&lt;br /&gt;
* [[ Исключения | Методы обработки ошибок. Исключения. Гарантии исключений. Евгений Баталов. 01.04.2011 ]]&lt;br /&gt;
* [[ Приведение типов. RTTI | Приведение типов. RTTI. Алексей Гуревич. 15.04.2011 ]]&lt;br /&gt;
* [[ Перегрузка операторов new и delete. Павел Синай ]]&lt;br /&gt;
* [[ Обзор библиотеки Boost ]]&lt;br /&gt;
* [[ Метапрограммирование на C++ | Метапрограммирование на C++. Александр Карташов. 06.05.2011 ]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=332</id>
		<title>Обзор библиотеки Boost</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B8_Boost&amp;diff=332"/>
				<updated>2011-05-31T07:55:13Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: Новая страница: «Мы рассмотрим несколько полезных модулей библиотеки Boost,  == Умные указатели ==»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько полезных модулей библиотеки Boost,&lt;br /&gt;
&lt;br /&gt;
== Умные указатели ==&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=323</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=323"/>
				<updated>2011-05-30T10:39:47Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры] --- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] --- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции] и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы], работающие с метаконтейнерами.&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция], позволяющая определить наличие определения псевдонима типа внутри класса.&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt; с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;mpl::push_back&amp;lt;numbers, mpl::int_&amp;lt;2&amp;gt; &amp;gt;::type, 3&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Осмысленный пример использования метаконтейнеров --- реализация концепции единиц измерения на С++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
  using namespace boost;&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;int kg, int m, int s&amp;gt;&lt;br /&gt;
  struct unit {&lt;br /&gt;
    typedef mpl::vector&amp;lt;mpl::int_&amp;lt;kg&amp;gt;, mpl::int_&amp;lt;m&amp;gt;, mpl::int_&amp;lt;s&amp;gt; &amp;gt; u;&lt;br /&gt;
&lt;br /&gt;
    float value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  typedef unit&amp;lt;1, 0, 0&amp;gt; mass;&lt;br /&gt;
  typedef unit&amp;lt;0, 1, -1&amp;gt; velocity;&lt;br /&gt;
  typedef unit&amp;lt;0, 1, -2&amp;gt; acceleration;&lt;br /&gt;
  typedef unit&amp;lt;1, 1, -1&amp;gt; momentum;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=308</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=308"/>
				<updated>2011-05-29T17:51:34Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры] --- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] --- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции] и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы], работающие с метаконтейнерами.&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt; с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;mpl::push_back&amp;lt;numbers, mpl::int_&amp;lt;2&amp;gt; &amp;gt;::type, 3&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Осмысленный пример использования метаконтейнеров: реализация концепции единиц измерения на С++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
  using namespace boost;&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;int kg, int m, int s&amp;gt;&lt;br /&gt;
  struct unit {&lt;br /&gt;
    typedef mpl::vector&amp;lt;mpl::int_&amp;lt;kg&amp;gt;, mpl::int_&amp;lt;m&amp;gt;, mpl::int_&amp;lt;s&amp;gt; &amp;gt; u;&lt;br /&gt;
&lt;br /&gt;
    float value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  typedef unit&amp;lt;1, 0, 0&amp;gt; mass;&lt;br /&gt;
  typedef unit&amp;lt;0, 1, -1&amp;gt; velocity;&lt;br /&gt;
  typedef unit&amp;lt;0, 1, -2&amp;gt; acceleration;&lt;br /&gt;
  typedef unit&amp;lt;1, 1, -1&amp;gt; momentum;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=307</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=307"/>
				<updated>2011-05-29T17:48:20Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры] --- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] --- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции] и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы], работающие с метаконтейнерами.&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt; с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
   std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;mpl::push_back&amp;lt;numbers, mpl::int_&amp;lt;2&amp;gt; &amp;gt;::type, 3&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 2&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Осмысленный пример использования метаконтейнеров: реализация концепции единиц измерения на С++:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
  using namespace boost;&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;int kg, int m, int s&amp;gt;&lt;br /&gt;
  struct unit {&lt;br /&gt;
    typedef mpl::vector&amp;lt;mpl::int_&amp;lt;kg&amp;gt;, mpl::int_&amp;lt;m&amp;gt;, mpl::int_&amp;lt;s&amp;gt; &amp;gt; u;&lt;br /&gt;
&lt;br /&gt;
    float value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  typedef unit&amp;lt;1, 0, 0&amp;gt; mass;&lt;br /&gt;
  typedef unit&amp;lt;0, 1, -1&amp;gt; velocity;&lt;br /&gt;
  typedef unit&amp;lt;0, 1, -2&amp;gt; acceleration;&lt;br /&gt;
  typedef unit&amp;lt;1, 1, -1&amp;gt; momentum;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=306</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=306"/>
				<updated>2011-05-29T17:26:35Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры] --- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] --- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции] и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы], работающие с метаконтейнерами.&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt; с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=305</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=305"/>
				<updated>2011-05-29T17:25:12Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры] --- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] --- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции], работающие с метаконтейнерами, и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt; с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=304</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=304"/>
				<updated>2011-05-29T17:24:49Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры] --- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] --- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции], работающие с метаконтейнерами, и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция].&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;&lt;br /&gt;
с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=303</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=303"/>
				<updated>2011-05-29T17:23:43Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html Метаконтейнеры]&lt;br /&gt;
--- аналоги контейнеров STL, существующие только в момент компиляции &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html Метаитераторы] &lt;br /&gt;
--- аналоги итераторов STL, работающие с метаконтейнерами: &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html Метафункции], &lt;br /&gt;
работающие с метаконтейнерами, и [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html метаалгоритмы]&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html Статическая интроспекция]&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html Статический Assert] --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;&lt;br /&gt;
с более подробным сообщением об ошибке (как заверяют разработчики).&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Вот простейший пример использования метаконтейнеров:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/vector.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;boost/mpl/int.hpp&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;typeinfo&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
using namespace boost;&lt;br /&gt;
&lt;br /&gt;
typedef mpl::vector&amp;lt;int, mpl::int_&amp;lt;1&amp;gt;, double&amp;gt; numbers;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  std::cout &amp;lt;&amp;lt; mpl::v_at&amp;lt;numbers, 1&amp;gt;::type::value &amp;lt;&amp;lt; std::endl; // Выводит 1&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=277</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=277"/>
				<updated>2011-05-29T09:22:28Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* Метаконтейнеры --- аналоги контейнеров STL, существующие только в момент компиляции [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html]&lt;br /&gt;
* Метаитераторы --- аналоги итераторов STL, работающие с метаконтейнерами: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html]&lt;br /&gt;
* Метафункции, работающие с метаконтейнерами: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html] и метаалгоритмы: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html]&lt;br /&gt;
* Статическая интроспекция: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html]&lt;br /&gt;
* Статический Assert --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html]&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=276</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=276"/>
				<updated>2011-05-29T09:21:21Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* Метаконтейнеры --- аналоги контейнеров STL, существующие только в момент компиляции&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html]&lt;br /&gt;
* Метаитераторы --- аналоги итераторов STL, работающие с метаконтейнерами:&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html]&lt;br /&gt;
* Метафункции, работающие с метаконтейнерами: &lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html]&lt;br /&gt;
  и метаалгоритмы:&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html]&lt;br /&gt;
* Статическая интроспекция: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html]&lt;br /&gt;
* Статический Assert --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;: &lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html]&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=275</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=275"/>
				<updated>2011-05-29T09:16:43Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* Метаконтейнеры --- аналоги контейнеров STL, существующие только в момент компиляции&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html]&lt;br /&gt;
* Метаитераторы --- аналоги итераторов STL, работающие с метаконтейнерами:&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/concepts.html]&lt;br /&gt;
* Метафункции, работающие с метаконтейнерами: &lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/intrinsic-metafunctions.html]&lt;br /&gt;
  и метаалгоритмы:&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/algorithms.html]&lt;br /&gt;
* Статическая интроспекция: [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/introspection.html]&lt;br /&gt;
* Статический Assert --- аналог &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;: &lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/asserts.html]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=274</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=274"/>
				<updated>2011-05-29T09:06:03Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple]&lt;br /&gt;
&lt;br /&gt;
Модули, входящие в состав модуля MPL:&lt;br /&gt;
&lt;br /&gt;
* Метапоследовательности --- аналоги контейнеров STL, существующие только в момент компиляции&lt;br /&gt;
  [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/classes.html]&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=264</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=264"/>
				<updated>2011-05-25T20:41:22Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple] --- какие еще алгебраические типы данных реализует Boost?&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=263</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=263"/>
				<updated>2011-05-23T18:07:53Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобен при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple].&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=262</id>
		<title>Файл:Swoon2.gif</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=262"/>
				<updated>2011-05-23T18:00:47Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: загружена новая версия «Файл:Swoon2.gif»:&amp;amp;#32;Source: http://redhat-club.org/forum/img/smilies/swoon2.gif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=261</id>
		<title>Файл:Swoon2.gif</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=261"/>
				<updated>2011-05-23T17:59:53Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: Удалено содержимое страницы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=260</id>
		<title>Файл:Swoon2.gif</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=260"/>
				<updated>2011-05-23T17:59:28Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;http://redhat-club.org/forum/img/smilies/swoon2.gif&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=259</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=259"/>
				<updated>2011-05-23T17:57:07Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple].&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.gif]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=258</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=258"/>
				<updated>2011-05-23T17:55:41Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple].&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=257</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=257"/>
				<updated>2011-05-23T17:55:02Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple].&lt;br /&gt;
&lt;br /&gt;
[[Файл:Swoon2.png]]&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=256</id>
		<title>Файл:Swoon2.gif</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Swoon2.gif&amp;diff=256"/>
				<updated>2011-05-23T17:54:00Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=255</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=255"/>
				<updated>2011-05-23T17:46:00Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;br /&gt;
&lt;br /&gt;
Модули Boost, реализующие некоторые концепции языков функционального программирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html bind] и [http://www.boost.org/doc/libs/1_46_1/libs/bind/mem_fn.html mem_fn],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/lambda.html lambda],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/function.html function],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/tuple/doc/tuple_users_guide.html tuple].&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=254</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=254"/>
				<updated>2011-05-23T17:37:11Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Реализовать красно-черные деревья на шаблонах :).&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=253</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=253"/>
				<updated>2011-05-23T17:36:08Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/in_place_factories.html in_place_factory, typed_in_place_factory],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/operators.htm operators], &lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/property_map/doc/property_map.html property map],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html static_assert],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/index.html type_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/fusion/doc/html/index.html fusion],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/index.html mpl],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/doc/html/proto.html proto].&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=252</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=252"/>
				<updated>2011-05-23T17:32:42Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем [http://www.boost.org/doc/libs/1_46_1/doc/html/boost_staticassert.html &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt;]&lt;br /&gt;
библиотеки Boost.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;br /&gt;
&lt;br /&gt;
== Поддержка метапрограммирования в Boost ==&lt;br /&gt;
&lt;br /&gt;
Вот список модулей библиотеки Boost, реализующих некоторые фичи (sic!) &lt;br /&gt;
метапрограммирования:&lt;br /&gt;
&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/call_traits.htm call_traits],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm concept check],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html enable_if],&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_46_1/libs/function_types/doc/html/index.html function_types],&lt;br /&gt;
* gil,&lt;br /&gt;
* in_place_factory, typed_in_place_factory,&lt;br /&gt;
* operators, &lt;br /&gt;
* property map,&lt;br /&gt;
* static_assert,&lt;br /&gt;
* type_traits,&lt;br /&gt;
* function_types,&lt;br /&gt;
* fusion,&lt;br /&gt;
* mpl,&lt;br /&gt;
* proto.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=251</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=251"/>
				<updated>2011-05-23T17:21:37Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt; библиотеки &amp;lt;code&amp;gt;Boost&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип [http://www.boost.org/doc/libs/1_46_1/libs/utility/enable_if.html &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;], &lt;br /&gt;
который позволяет решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=250</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=250"/>
				<updated>2011-05-23T17:19:19Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt; библиотеки &amp;lt;code&amp;gt;Boost&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, который позволяет&lt;br /&gt;
решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; ведет себя так же, как и &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, но более удобна при&lt;br /&gt;
использовании trait'ов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;class T, class Enable = void&amp;gt; &lt;br /&gt;
class A { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
class A&amp;lt;T, typename enable_if&amp;lt;is_float&amp;lt;T&amp;gt; &amp;gt;::type&amp;gt; { ... };&lt;br /&gt;
&amp;lt;/sorce&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере &amp;lt;code&amp;gt;enable_if&amp;lt;/code&amp;gt; позволяет выбирать конкретную специализацию &lt;br /&gt;
шаблона класса &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; в зависимости от того, является ли тип &amp;lt;code&amp;gt;T&amp;lt;/code&amp;gt;&lt;br /&gt;
целочисленным или вещественнозначным.&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	<entry>
		<id>http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=249</id>
		<title>Метапрограммирование на C++</title>
		<link rel="alternate" type="text/html" href="http://mit.spbau.ru/sewiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BD%D0%B0_C%2B%2B&amp;diff=249"/>
				<updated>2011-05-23T17:13:42Z</updated>
		
		<summary type="html">&lt;p&gt;Aleksandr.kartashov: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Мы рассмотрим несколько &amp;lt;&amp;lt;необычных&amp;gt;&amp;gt; примеров использования шаблонов C++.&lt;br /&gt;
&lt;br /&gt;
== Статический &amp;lt;code&amp;gt;assert&amp;lt;/code&amp;gt; ==&lt;br /&gt;
В следующем примере приведен код, который компилируется только&lt;br /&gt;
на 64-разрядной платформе:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
char a[sizeof(int*) == 8 ? 1 : -1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если код компилируется не на 64-разрядной платформе, то&lt;br /&gt;
&amp;lt;code&amp;gt;sizeof(int*) != 8&amp;lt;/code&amp;gt;, что приведет к объявлению массива a отрицательного&lt;br /&gt;
размера, а это запрещено стандартом.&lt;br /&gt;
&lt;br /&gt;
Эта идея используется в макросе &amp;lt;code&amp;gt;BOOST_STATIC_ASSERT&amp;lt;/code&amp;gt;, предоставляемом&lt;br /&gt;
модулем &amp;lt;code&amp;gt;Static Assert&amp;lt;/code&amp;gt; библиотеки &amp;lt;code&amp;gt;Boost&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Tag passing ==&lt;br /&gt;
&lt;br /&gt;
Предположим, нам нужно написать функцию, которая циклически &lt;br /&gt;
переставляет элементы массива:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
где &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; --- итераторы, указывающие на начало и конец массива, &lt;br /&gt;
а элемент, на который указывает &amp;lt;code&amp;gt;m&amp;lt;/code&amp;gt;, после завершения работы функции будет располагаться&lt;br /&gt;
на месте элемента, на который указывает &amp;lt;code&amp;gt;p&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_bidirectional(It p, It, m, It q);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate_random_access(It p, It, m, It q);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести&lt;br /&gt;
информацию о типе итератора, с которым работает эта функция, из ее имени в этот&lt;br /&gt;
параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, bidirectional_tag);&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q, random_access_tag);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда исходную функцию можно реализовать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename It&amp;gt;&lt;br /&gt;
void rotate(It p, It, m, It q) {&lt;br /&gt;
  rotate(p, m, q, iterator_traits&amp;lt;It&amp;gt;::iterator_category());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Замена числовых идентификаторов на типы ==&lt;br /&gt;
&lt;br /&gt;
С помощью следующего трюка можно переписать функцию, поведение которой &lt;br /&gt;
зависит от числового идентификатора, так, чтобы ее поведение зависело от&lt;br /&gt;
формального параметра (как в предыдущем разделе):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void foo(int);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы можем определить шаблонную структуру:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
struct int2type { static const int value = i; };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь функцию foo можно переписать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;int i&amp;gt;&lt;br /&gt;
void foo(int2type&amp;lt;i&amp;gt;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Substitution Failure Is Not An Error (SFINAE) ==&lt;br /&gt;
При создании экземпляров шаблонных функций могут возникать компиляции.&lt;br /&gt;
Рассмотрим следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int diff(int a, int b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
typename T::diff_type diff(T a, T b) {&lt;br /&gt;
  return a - b;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При вызове &amp;lt;code&amp;gt;diff(3, 4)&amp;lt;/code&amp;gt; компилятор попытается создать экземпляр&lt;br /&gt;
функции &amp;lt;code&amp;gt;diff&amp;lt;int&amp;gt;(int, int)&amp;lt;/code&amp;gt;, но это приведет к ошибке компиляции,&lt;br /&gt;
поскольку &amp;lt;code&amp;gt;int::diff_type&amp;lt;/code&amp;gt; не определено. Но эта ошибка не приводит &lt;br /&gt;
к выдаче сообщения об ошибке и прекращению компиляции, поскольку есть нешаблонная&lt;br /&gt;
функция c подходящей сигнатурой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
С помощью SFINAE можно управлять разрешением перегруженных шаблонных функций.&lt;br /&gt;
В библиотеке Boost есть шаблонный тип &amp;lt;code&amp;gt;enable_if_c&amp;lt;/code&amp;gt;, который позволяет&lt;br /&gt;
решить эту задачу. Он определен следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template &amp;lt;bool B, class T = void&amp;gt;&lt;br /&gt;
struct enable_if_c {&lt;br /&gt;
  typedef T type;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class T&amp;gt;&lt;br /&gt;
struct enable_if_c&amp;lt;false, T&amp;gt; {};&lt;br /&gt;
&lt;br /&gt;
template &amp;lt;class Cond, class T = void&amp;gt;&lt;br /&gt;
struct enable_if : public enable_if_c&amp;lt;Cond::value, T&amp;gt; {};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, конструкция &amp;lt;code&amp;gt;enable_if_c&amp;lt;false, T&amp;gt;::type&amp;lt;/code&amp;gt; вызовет ошибку компиляции.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Проверка наличия метода у класса ==&lt;br /&gt;
&lt;br /&gt;
В следующем примере показано, как с помощью шаблонов можно проверить &lt;br /&gt;
наличие метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; у класса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef char true_type;&lt;br /&gt;
class false_type { true_type a[2]; };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T, size_t (T::*)() const&amp;gt;&lt;br /&gt;
struct wrap { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, wrap&amp;lt;T, &amp;amp;T::size&amp;gt; = wrap&amp;lt;T, &amp;amp;T::size&amp;gt;()) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
false_type check(void*) { }&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
struct check_size {&lt;br /&gt;
  static const bool value = sizeof(check&amp;lt;T&amp;gt;((T*)0)) == sizeof(true_type);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class bar {&lt;br /&gt;
  void no_size() { }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
  if (check_size&amp;lt;std::vector&amp;lt;int&amp;gt; &amp;gt;::value == true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Vector has a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (check_size&amp;lt;bar&amp;gt;::value != true) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Bar doesn't have a size field!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;lt;/code&amp;gt; создается&lt;br /&gt;
первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку можно без проблем создать&lt;br /&gt;
экземпляр структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; создается второй вариант &lt;br /&gt;
функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;, поскольку создание экземпляра структуры &amp;lt;code&amp;gt;wrap&amp;lt;/code&amp;gt;&lt;br /&gt;
приводит к ошибке.&lt;br /&gt;
&lt;br /&gt;
''Замечание'' Я не совсем понял, почему нельзя первый вариант функции &amp;lt;code&amp;gt;check_size&amp;lt;/code&amp;gt;&lt;br /&gt;
написать так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
true_type check(T*, size_t (T::*)() const = &amp;amp;T::size) { };&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При создании экземпляра класса &amp;lt;code&amp;gt;check_size&amp;lt;bar&amp;gt;&amp;lt;/code&amp;gt; компилятор говорит, что &lt;br /&gt;
у класса &amp;lt;code&amp;gt;bar&amp;lt;/code&amp;gt; нет метода &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;. В этом случае SFINAE не работает?&lt;br /&gt;
&lt;br /&gt;
== Списки типов ==&lt;br /&gt;
На шаблонах можно реализовать списки в функциональном стиле. Правда, такие списки&lt;br /&gt;
будут существовать только во время компиляции.&lt;br /&gt;
&lt;br /&gt;
Сначала реализуем общее описание списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
struct nil { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename F, typename S = nil&amp;gt;&lt;br /&gt;
struct cons {&lt;br /&gt;
  typedef F head;&lt;br /&gt;
  typedef S tail;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тогда список из трех элементов можно описать так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
typedef cons&amp;lt;A, cons&amp;lt;B, cons&amp;lt;C&amp;gt; &amp;gt; type_list;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно унаследовать класс от всех классов, входящих в список:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
template&amp;lt;typename L&amp;gt;&lt;br /&gt;
struct inherit : L::head, inherit&amp;lt;typename L::tail&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;&amp;gt;&lt;br /&gt;
struct inherit&amp;lt;nil&amp;gt; { };&lt;br /&gt;
&lt;br /&gt;
struct D : inherit&amp;lt;type_list&amp;gt;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt; будет унаследована от структур &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;, &lt;br /&gt;
&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Задача''' Найти способ вызвать общую функцию у всех родителей.&lt;/div&gt;</summary>
		<author><name>Aleksandr.kartashov</name></author>	</entry>

	</feed>